26
26
#include "btree_private.h"
27
27
#include "fdw.h"
28
28
29
+ static int get_split_item_size (Page p , OffsetNumber newoffset ,
30
+ LocationIndex newitem_size , bool replace , OffsetNumber offset );
31
+ static OffsetNumber find_split_location (Page p , OffsetNumber offset ,
32
+ LocationIndex tuplesize , bool replace , float target_ratio );
29
33
static PageNumber btree_split (BTreeDescr * desc , Page p , OffsetNumber * offset ,
30
34
bool * place_right , Pointer tupleheader , Pointer tuple ,
31
35
OffsetNumber tuplesize , bool replace , uint32 * state , CommitSeqNo * csn );
@@ -54,6 +58,117 @@ init_btree(BTreeDescr *desc)
54
58
init_meta_page (GET_PAGE (desc -> meta ), 1 );
55
59
}
56
60
61
+ /*
62
+ * Get size of item during split consideration.
63
+ */
64
+ static int
65
+ get_split_item_size (Page p , OffsetNumber newoffset , LocationIndex newitem_size ,
66
+ bool replace , OffsetNumber offset )
67
+ {
68
+ if (offset < newoffset )
69
+ return BTREE_PAGE_GET_ITEM_SIZE (p , offset ) + sizeof (OffsetNumber );
70
+ else if (offset == newoffset )
71
+ return newitem_size + sizeof (OffsetNumber );
72
+ else if (replace )
73
+ return BTREE_PAGE_GET_ITEM_SIZE (p , offset ) + sizeof (OffsetNumber );
74
+ else
75
+ return BTREE_PAGE_GET_ITEM_SIZE (p , offset - 1 ) + sizeof (OffsetNumber );
76
+ }
77
+
78
+ /*
79
+ * Find appropriate location to split. Return number of tuples to be placed
80
+ * to the left page.
81
+ */
82
+ static OffsetNumber
83
+ find_split_location (Page p , OffsetNumber offset , LocationIndex tuplesize ,
84
+ bool replace , float target_ratio )
85
+ {
86
+ int left_free_space ;
87
+ int right_free_space ;
88
+ int left_bound ;
89
+ int right_bound ;
90
+ int first_data_key = BTREE_FIRST_DATA_KEY (p );
91
+ int count ;
92
+ bool left_bounded = false;
93
+ bool right_bounded = false;
94
+ bool leaf = PAGE_IS_LEAF (p );
95
+ LocationIndex header_size = leaf ? OLeafTupleHeaderSize : OInternalTupleHeaderSize ;
96
+ LocationIndex newitem_size = sizeof (OffsetNumber ) + header_size + tuplesize ;
97
+ LocationIndex item_size ;
98
+
99
+ /*
100
+ * Covert ratio of fillfactor to ratio of free space.
101
+ */
102
+ target_ratio = target_ratio / (1.0 - target_ratio );
103
+
104
+ count = BTREE_PAGE_ITEMS_COUNT (p ) - first_data_key + (replace ? 0 : 1 );
105
+ left_free_space = right_free_space = IN_MEMORY_BLCKSZ - offsetof(BTreePageHeader , items );
106
+
107
+ /*
108
+ * Left and right pages initially contain one item each. Left page also
109
+ * reserves space for high key. For leafs, We assume that high key
110
+ * couldn't be wider than than source tuple.
111
+ */
112
+ left_bound = 1 ;
113
+ left_free_space -= get_split_item_size (p , offset , newitem_size ,
114
+ replace , first_data_key );
115
+ left_free_space -= get_split_item_size (p , offset , newitem_size ,
116
+ replace , first_data_key + 1 );
117
+
118
+ right_bound = count - 1 ;
119
+ right_free_space -= get_split_item_size (p , offset , newitem_size ,
120
+ replace , first_data_key + count - 1 );
121
+ if (!PAGE_IS_RIGHTMOST (p ))
122
+ right_free_space -= BTREE_PAGE_GET_ITEM_SIZE (p , BTREE_HIKEY ) + sizeof (OffsetNumber );
123
+
124
+ Assert (left_free_space >= 0 && right_free_space >= 0 );
125
+
126
+ /*
127
+ * Iterate shifting left bound upper and right bound lower until those
128
+ * bounds meet each other.
129
+ */
130
+ while (left_bound < right_bound )
131
+ {
132
+ if (right_bounded || (!left_bounded &&
133
+ (float ) left_free_space * target_ratio > (float ) right_free_space ))
134
+ {
135
+ Assert (!left_bounded );
136
+ item_size = get_split_item_size (p , offset , newitem_size , replace ,
137
+ first_data_key + left_bound + 1 );
138
+ if (left_free_space >= item_size )
139
+ {
140
+ left_free_space -= item_size ;
141
+ left_bound ++ ;
142
+ }
143
+ else
144
+ {
145
+ left_bounded = true;
146
+ }
147
+ }
148
+ else
149
+ {
150
+ Assert (!right_bounded );
151
+ item_size = get_split_item_size (p , offset , newitem_size , replace ,
152
+ first_data_key + right_bound - 1 );
153
+ if (right_free_space >= item_size )
154
+ {
155
+ right_free_space -= item_size ;
156
+ right_bound -- ;
157
+ }
158
+ else
159
+ {
160
+ right_bounded = true;
161
+ }
162
+ }
163
+ }
164
+
165
+ Assert (left_bound == right_bound );
166
+ return left_bound ;
167
+ }
168
+
169
+ /*
170
+ * Split B-tree page into two.
171
+ */
57
172
static PageNumber
58
173
btree_split (BTreeDescr * desc , Page p , OffsetNumber * offset , bool * place_right ,
59
174
Pointer tupleheader , Pointer tuple , LocationIndex tuplesize ,
@@ -85,7 +200,10 @@ btree_split(BTreeDescr *desc, Page p, OffsetNumber *offset, bool *place_right,
85
200
{
86
201
right_count = count / 2 ;
87
202
}
88
- left_count = (count - right_count ) + BTREE_FIRST_DATA_KEY (p );
203
+ left_count = find_split_location (p , * offset , tuplesize , replace ,
204
+ was_rightmost ? 0.9 : 0.5 );
205
+ right_count = count - left_count ;
206
+ left_count += BTREE_FIRST_DATA_KEY (p );
89
207
if (* offset < left_count )
90
208
{
91
209
* place_right = false;
@@ -162,27 +280,20 @@ btree_split(BTreeDescr *desc, Page p, OffsetNumber *offset, bool *place_right,
162
280
new_header -> csn = * csn ;
163
281
new_header -> undoPos = undo_pos ;
164
282
165
- /* Insert tuple */
283
+ /* Insert new tuple to the right page if needed */
166
284
if (* place_right )
167
285
{
168
286
if (!replace )
169
287
add_page_item (new_page , * offset , MAXALIGN (tuplesize ) + header_size );
170
288
else
171
289
resize_page_item (new_page , * offset , MAXALIGN (tuplesize ) + header_size );
172
290
tuple_ptr = BTREE_PAGE_GET_ITEM (new_page , * offset );
291
+ memcpy (tuple_ptr , tupleheader , header_size );
292
+ tuple_ptr += header_size ;
293
+ memcpy (tuple_ptr , tuple , tuplesize );
173
294
}
174
- else
175
- {
176
- if (!replace )
177
- add_page_item (p , * offset , MAXALIGN (tuplesize ) + header_size );
178
- else
179
- resize_page_item (p , * offset , MAXALIGN (tuplesize ) + header_size );
180
- tuple_ptr = BTREE_PAGE_GET_ITEM (p , * offset );
181
- }
182
- memcpy (tuple_ptr , tupleheader , header_size );
183
- tuple_ptr += header_size ;
184
- memcpy (tuple_ptr , tuple , tuplesize );
185
295
296
+ /* Update high key of left page */
186
297
first_data_key = BTREE_FIRST_DATA_KEY (new_page );
187
298
rightbound_key = BTREE_PAGE_GET_ITEM (new_page , first_data_key ) + header_size ;
188
299
if (leaf )
@@ -197,13 +308,33 @@ btree_split(BTreeDescr *desc, Page p, OffsetNumber *offset, bool *place_right,
197
308
}
198
309
199
310
if (was_rightmost )
311
+ {
312
+ if (!(* place_right ))
313
+ (* offset )++ ;
200
314
add_page_item (p , BTREE_HIKEY , MAXALIGN (rightbound_key_size ));
315
+ }
201
316
else
317
+ {
202
318
resize_page_item (p , BTREE_HIKEY , MAXALIGN (rightbound_key_size ));
319
+ }
203
320
204
321
memcpy (BTREE_PAGE_GET_ITEM (p , BTREE_HIKEY ),
205
322
rightbound_key , rightbound_key_size );
206
323
324
+ /* Insert new tuple to the left page if needed */
325
+ if (!(* place_right ))
326
+ {
327
+ if (!replace )
328
+ add_page_item (p , * offset , MAXALIGN (tuplesize ) + header_size );
329
+ else
330
+ resize_page_item (p , * offset , MAXALIGN (tuplesize ) + header_size );
331
+ tuple_ptr = BTREE_PAGE_GET_ITEM (p , * offset );
332
+ memcpy (tuple_ptr , tupleheader , header_size );
333
+ tuple_ptr += header_size ;
334
+ memcpy (tuple_ptr , tuple , tuplesize );
335
+ }
336
+
337
+
207
338
#ifdef NOT_USED
208
339
/* Remove leftmost key from the page */
209
340
if (!leaf )
0 commit comments