8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.151 2007/02/08 13:52:55 alvherre Exp $
11
+ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.152 2007/02/21 20:02:17 momjian Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -29,6 +29,10 @@ typedef struct
29
29
int fillfactor ; /* needed when splitting rightmost page */
30
30
bool is_leaf ; /* T if splitting a leaf page */
31
31
bool is_rightmost ; /* T if splitting a rightmost page */
32
+ OffsetNumber newitemoff ; /* where the new item is to be inserted */
33
+ int leftspace ; /* space available for items on left page */
34
+ int rightspace ; /* space available for items on right page */
35
+ int olddataitemstotal ; /* space taken by old items */
32
36
33
37
bool have_split ; /* found a valid split? */
34
38
@@ -57,9 +61,9 @@ static OffsetNumber _bt_findsplitloc(Relation rel, Page page,
57
61
OffsetNumber newitemoff ,
58
62
Size newitemsz ,
59
63
bool * newitemonleft );
60
- static void _bt_checksplitloc (FindSplitData * state , OffsetNumber firstright ,
61
- int leftfree , int rightfree ,
62
- bool newitemonleft , Size firstrightitemsz );
64
+ static void _bt_checksplitloc (FindSplitData * state ,
65
+ OffsetNumber firstoldonright , bool newitemonleft ,
66
+ int dataitemstoleft , Size firstoldonrightsz );
63
67
static void _bt_pgaddtup (Relation rel , Page page ,
64
68
Size itemsize , IndexTuple itup ,
65
69
OffsetNumber itup_off , const char * where );
@@ -1101,13 +1105,31 @@ _bt_findsplitloc(Relation rel,
1101
1105
int leftspace ,
1102
1106
rightspace ,
1103
1107
goodenough ,
1104
- dataitemtotal ,
1105
- dataitemstoleft ;
1108
+ olddataitemstotal ,
1109
+ olddataitemstoleft ;
1110
+ bool goodenoughfound ;
1106
1111
1107
1112
opaque = (BTPageOpaque ) PageGetSpecialPointer (page );
1108
1113
1109
1114
/* Passed-in newitemsz is MAXALIGNED but does not include line pointer */
1110
1115
newitemsz += sizeof (ItemIdData );
1116
+
1117
+ /* Total free space available on a btree page, after fixed overhead */
1118
+ leftspace = rightspace =
1119
+ PageGetPageSize (page ) - SizeOfPageHeaderData -
1120
+ MAXALIGN (sizeof (BTPageOpaqueData ));
1121
+
1122
+ /* The right page will have the same high key as the old page */
1123
+ if (!P_RIGHTMOST (opaque ))
1124
+ {
1125
+ itemid = PageGetItemId (page , P_HIKEY );
1126
+ rightspace -= (int ) (MAXALIGN (ItemIdGetLength (itemid )) +
1127
+ sizeof (ItemIdData ));
1128
+ }
1129
+
1130
+ /* Count up total space in data items without actually scanning 'em */
1131
+ olddataitemstotal = rightspace - (int ) PageGetExactFreeSpace (page );
1132
+
1111
1133
state .newitemsz = newitemsz ;
1112
1134
state .is_leaf = P_ISLEAF (opaque );
1113
1135
state .is_rightmost = P_RIGHTMOST (opaque );
@@ -1120,11 +1142,10 @@ _bt_findsplitloc(Relation rel,
1120
1142
state .newitemonleft = false; /* these just to keep compiler quiet */
1121
1143
state .firstright = 0 ;
1122
1144
state .best_delta = 0 ;
1123
-
1124
- /* Total free space available on a btree page, after fixed overhead */
1125
- leftspace = rightspace =
1126
- PageGetPageSize (page ) - SizeOfPageHeaderData -
1127
- MAXALIGN (sizeof (BTPageOpaqueData ));
1145
+ state .leftspace = leftspace ;
1146
+ state .rightspace = rightspace ;
1147
+ state .olddataitemstotal = olddataitemstotal ;
1148
+ state .newitemoff = newitemoff ;
1128
1149
1129
1150
/*
1130
1151
* Finding the best possible split would require checking all the possible
@@ -1137,74 +1158,60 @@ _bt_findsplitloc(Relation rel,
1137
1158
*/
1138
1159
goodenough = leftspace / 16 ;
1139
1160
1140
- /* The right page will have the same high key as the old page */
1141
- if (!P_RIGHTMOST (opaque ))
1142
- {
1143
- itemid = PageGetItemId (page , P_HIKEY );
1144
- rightspace -= (int ) (MAXALIGN (ItemIdGetLength (itemid )) +
1145
- sizeof (ItemIdData ));
1146
- }
1147
-
1148
- /* Count up total space in data items without actually scanning 'em */
1149
- dataitemtotal = rightspace - (int ) PageGetFreeSpace (page );
1150
-
1151
1161
/*
1152
1162
* Scan through the data items and calculate space usage for a split at
1153
1163
* each possible position.
1154
1164
*/
1155
- dataitemstoleft = 0 ;
1165
+ olddataitemstoleft = 0 ;
1166
+ goodenoughfound = false;
1156
1167
maxoff = PageGetMaxOffsetNumber (page );
1157
-
1168
+
1158
1169
for (offnum = P_FIRSTDATAKEY (opaque );
1159
1170
offnum <= maxoff ;
1160
1171
offnum = OffsetNumberNext (offnum ))
1161
1172
{
1162
1173
Size itemsz ;
1163
- int leftfree ,
1164
- rightfree ;
1165
1174
1166
1175
itemid = PageGetItemId (page , offnum );
1167
1176
itemsz = MAXALIGN (ItemIdGetLength (itemid )) + sizeof (ItemIdData );
1168
1177
1169
- /*
1170
- * We have to allow for the current item becoming the high key of the
1171
- * left page; therefore it counts against left space as well as right
1172
- * space.
1173
- */
1174
- leftfree = leftspace - dataitemstoleft - (int ) itemsz ;
1175
- rightfree = rightspace - (dataitemtotal - dataitemstoleft );
1176
-
1177
1178
/*
1178
1179
* Will the new item go to left or right of split?
1179
1180
*/
1180
1181
if (offnum > newitemoff )
1181
- _bt_checksplitloc (& state , offnum , leftfree , rightfree ,
1182
- true, itemsz );
1182
+ _bt_checksplitloc (& state , offnum , true,
1183
+ olddataitemstoleft , itemsz );
1184
+
1183
1185
else if (offnum < newitemoff )
1184
- _bt_checksplitloc (& state , offnum , leftfree , rightfree ,
1185
- false , itemsz );
1186
+ _bt_checksplitloc (& state , offnum , false,
1187
+ olddataitemstoleft , itemsz );
1186
1188
else
1187
1189
{
1188
1190
/* need to try it both ways! */
1189
- _bt_checksplitloc (& state , offnum , leftfree , rightfree ,
1190
- true, itemsz );
1191
- /*
1192
- * Here we are contemplating newitem as first on right. In this
1193
- * case it, not the current item, will become the high key of the
1194
- * left page, and so we have to correct the allowance made above.
1195
- */
1196
- leftfree += (int ) itemsz - (int ) newitemsz ;
1197
- _bt_checksplitloc (& state , offnum , leftfree , rightfree ,
1198
- false, newitemsz );
1191
+ _bt_checksplitloc (& state , offnum , true,
1192
+ olddataitemstoleft , itemsz );
1193
+
1194
+ _bt_checksplitloc (& state , offnum , false,
1195
+ olddataitemstoleft , itemsz );
1199
1196
}
1200
1197
1201
1198
/* Abort scan once we find a good-enough choice */
1202
1199
if (state .have_split && state .best_delta <= goodenough )
1200
+ {
1201
+ goodenoughfound = true;
1203
1202
break ;
1203
+ }
1204
1204
1205
- dataitemstoleft += itemsz ;
1205
+ olddataitemstoleft += itemsz ;
1206
1206
}
1207
1207
1208
+ /* If the new item goes as the last item, check for splitting so that
1209
+ * all the old items go to the left page and the new item goes to the
1210
+ * right page.
1211
+ */
1212
+ if (newitemoff > maxoff && !goodenoughfound )
1213
+ _bt_checksplitloc (& state , newitemoff , false, olddataitemstotal , 0 );
1214
+
1208
1215
/*
1209
1216
* I believe it is not possible to fail to find a feasible split, but just
1210
1217
* in case ...
@@ -1220,15 +1227,50 @@ _bt_findsplitloc(Relation rel,
1220
1227
/*
1221
1228
* Subroutine to analyze a particular possible split choice (ie, firstright
1222
1229
* and newitemonleft settings), and record the best split so far in *state.
1230
+ *
1231
+ * firstoldonright is the offset of the first item on the original page
1232
+ * that goes to the right page, and firstoldonrightsz is the size of that
1233
+ * tuple. firstoldonright can be > max offset, which means that all the old
1234
+ * items go to the left page and only the new item goes to the right page.
1235
+ * In that case, firstoldonrightsz is not used.
1236
+ *
1237
+ * olddataitemstoleft is the total size of all old items to the left of
1238
+ * firstoldonright.
1223
1239
*/
1224
1240
static void
1225
- _bt_checksplitloc (FindSplitData * state , OffsetNumber firstright ,
1226
- int leftfree , int rightfree ,
1227
- bool newitemonleft , Size firstrightitemsz )
1241
+ _bt_checksplitloc (FindSplitData * state ,
1242
+ OffsetNumber firstoldonright ,
1243
+ bool newitemonleft ,
1244
+ int olddataitemstoleft ,
1245
+ Size firstoldonrightsz )
1228
1246
{
1247
+ int leftfree ,
1248
+ rightfree ;
1249
+ Size firstrightitemsz ;
1250
+ bool newitemisfirstonright ;
1251
+
1252
+ /* Is the new item going to be the first item on the right page? */
1253
+ newitemisfirstonright = (firstoldonright == state -> newitemoff
1254
+ && !newitemonleft );
1255
+
1256
+ if (newitemisfirstonright )
1257
+ firstrightitemsz = state -> newitemsz ;
1258
+ else
1259
+ firstrightitemsz = firstoldonrightsz ;
1260
+
1261
+ /* Account for all the old tuples */
1262
+ leftfree = state -> leftspace - olddataitemstoleft ;
1263
+ rightfree = state -> rightspace -
1264
+ (state -> olddataitemstotal - olddataitemstoleft );
1265
+
1229
1266
/*
1230
- * Account for the new item on whichever side it is to be put.
1267
+ * The first item on the right page becomes the high key of the
1268
+ * left page; therefore it counts against left space as well as right
1269
+ * space.
1231
1270
*/
1271
+ leftfree -= firstrightitemsz ;
1272
+
1273
+ /* account for the new item */
1232
1274
if (newitemonleft )
1233
1275
leftfree -= (int ) state -> newitemsz ;
1234
1276
else
@@ -1270,7 +1312,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
1270
1312
{
1271
1313
state -> have_split = true;
1272
1314
state -> newitemonleft = newitemonleft ;
1273
- state -> firstright = firstright ;
1315
+ state -> firstright = firstoldonright ;
1274
1316
state -> best_delta = delta ;
1275
1317
}
1276
1318
}
0 commit comments