Removed old deprecated c++ api.
[qt:qtjsondb.git] / src / 3rdparty / btree / src / btree.cpp
1 /*      $OpenBSD: btree.c,v 1.30 2010/09/01 12:13:21 martinh Exp $ */
2
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18
19 #include "btree.h"
20 #include "btree_p.h"
21
22 //#define ENABLE_BIG_KEYS
23
24 #ifdef ENABLE_BIG_KEYS
25 #warning "Big keys may cause unforseen circumstances. Avoid for now."
26 #endif
27
28 #undef DEBUG
29
30 #ifdef DEBUG
31 # define DPRINTF(...)   do { fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
32                              fprintf(stderr, __VA_ARGS__); \
33                              fprintf(stderr, "\n"); } while (0)
34 #else
35 # define DPRINTF(...) do { } while (0)
36 #endif
37
38 #ifndef NO_ERROR_MESSAGES
39 # define EPRINTF(...)   do { fprintf(stderr, "%s:%d: ", __func__, __LINE__); \
40                              fprintf(stderr, __VA_ARGS__); \
41                              fprintf(stderr, "\n"); } while (0)
42 #else
43 # define EPRINTF(...) do { } while (0)
44 #endif
45
46 static struct mpage     *mpage_lookup(struct btree *bt, pgno_t pgno);
47 static void              mpage_add(struct btree *bt, struct mpage *mp);
48 static void              mpage_free(struct mpage *mp);
49 static void              mpage_del(struct btree *bt, struct mpage *mp);
50 static void              mpage_flush(struct btree *bt);
51 static struct mpage     *mpage_copy(struct btree *bt, struct mpage *mp);
52 static void              mpage_prune(struct btree *bt);
53 static void              mpage_dirty(struct btree *bt, struct mpage *mp);
54 static struct mpage     *mpage_touch(struct btree *bt, struct mpage *mp);
55 static int               mpage_cmp(struct mpage *a, struct mpage *b);
56
57 RB_PROTOTYPE(page_cache, mpage, entry, mpage_cmp);
58 RB_GENERATE(page_cache, mpage, entry, mpage_cmp);
59
60 static int               btree_read_page(struct btree *bt, pgno_t pgno,
61                             struct page *page);
62 static struct mpage     *btree_get_mpage(struct btree *bt, pgno_t pgno);
63 enum SearchType {
64         SearchKey=0,
65         SearchFirst=1,
66         SearchLast=2,
67 };
68 static int               btree_search_page_root(struct btree *bt,
69                             struct mpage *root, struct btval *key,
70                             struct cursor *cursor, enum SearchType searchType, int modify,
71                             struct mpage **mpp);
72 static int               btree_search_page(struct btree *bt,
73                             struct btree_txn *txn, struct btval *key,
74                             struct cursor *cursor, enum SearchType searchType, int modify,
75                             struct mpage **mpp);
76
77 static int               btree_write_header(struct btree *bt, int fd);
78 static int               btree_read_header(struct btree *bt);
79 static int               btree_is_meta_page(struct btree *bt, struct page *p);
80 static int               btree_read_meta(struct btree *bt, pgno_t *p_next);
81 static int               btree_read_meta_with_tag(struct btree *bt, unsigned int tag, pgno_t *p_root);
82 static int               btree_write_meta(struct btree *bt, pgno_t root,
83                                           unsigned int flags, uint32_t tag);
84 static void              btree_ref(struct btree *bt);
85
86 static struct node      *btree_search_node(struct btree *bt, struct mpage *mp,
87                             struct btval *key, int *exactp, unsigned int *kip);
88 static int               btree_add_node(struct btree *bt, struct mpage *mp,
89                             indx_t indx, struct btval *key, struct btval *data,
90                             pgno_t pgno, uint8_t flags);
91 static void              btree_del_node(struct btree *bt, struct mpage *mp,
92                             indx_t indx);
93 static int               btree_read_data(struct btree *bt, struct mpage *mp,
94                             struct node *leaf, struct btval *data);
95
96 static int               btree_rebalance(struct btree *bt, struct mpage *mp);
97 static int               btree_update_key(struct btree *bt, struct mpage *mp,
98                             indx_t indx, struct btval *key);
99 static int               btree_adjust_prefix(struct btree *bt,
100                             struct mpage *src, int delta);
101 static int               btree_move_node(struct btree *bt, struct mpage *src,
102                             indx_t srcindx, struct mpage *dst, indx_t dstindx);
103 static int               btree_merge(struct btree *bt, struct mpage *src,
104                             struct mpage *dst);
105 static int               btree_split(struct btree *bt, struct mpage **mpp,
106                             unsigned int *newindxp, struct btval *newkey,
107                             struct btval *newdata, pgno_t newpgno);
108 static struct mpage     *btree_new_page(struct btree *bt, uint32_t flags);
109 static int               btree_write_overflow_data(struct btree *bt,
110                             struct page *p, struct btval *data);
111
112 static void              cursor_pop_page(struct cursor *cursor);
113 static struct ppage     *cursor_push_page(struct cursor *cursor,
114                             struct mpage *mp);
115
116 static int               bt_set_key(struct btree *bt, struct mpage *mp,
117                             struct node *node, struct btval *key);
118 static int               btree_sibling(struct cursor *cursor, int move_right, int rightmost);
119 static int               btree_cursor_next(struct cursor *cursor,
120                             struct btval *key, struct btval *data);
121 static int               btree_cursor_prev(struct cursor *cursor,
122                             struct btval *key, struct btval *data);
123 static int               btree_cursor_set(struct cursor *cursor,
124                             struct btval *key, struct btval *data, int *exactp);
125 static int               btree_cursor_first(struct cursor *cursor,
126                             struct btval *key, struct btval *data);
127
128 static void              bt_reduce_separator(struct btree *bt, struct node *min,
129                             struct btval *sep);
130 static void              remove_prefix(struct btree *bt, struct btval *key,
131                             size_t pfxlen);
132 static void              expand_prefix(struct btree *bt, struct mpage *mp,
133                             indx_t indx, struct btkey *expkey);
134 static void              concat_prefix(struct btree *bt, char *pfxstr, size_t pfxlen,
135                             char *keystr, size_t keylen,char *dest, size_t *size);
136 static void              common_prefix(struct btree *bt, struct btkey *min,
137                             struct btkey *max, struct btkey *pfx);
138 static void              find_common_prefix(struct btree *bt, struct mpage *mp);
139
140 static size_t            bt_leaf_size(struct btree *bt, struct mpage *mp, struct btval *key,
141                             struct btval *data);
142 static int               bt_is_overflow(struct btree *bt, struct mpage *mp, size_t ksize,
143                             size_t dsize);
144 static size_t            bt_branch_size(struct btree *bt, struct btval *key);
145
146 static pgno_t            btree_compact_tree(struct btree *bt, pgno_t pgno,
147                             struct btree *btc);
148
149 static int               memncmp(const void *s1, size_t n1,
150                             const void *s2, size_t n2, void *);
151 static int               memnrcmp(const void *s1, size_t n1,
152                             const void *s2, size_t n2, void *);
153
154 static uint32_t          calculate_crc32(const char *begin, const char *end);
155 static uint32_t          calculate_checksum(struct btree *bt, const struct page *p);
156 static int               verify_checksum(struct btree *bt, const struct page *page);
157
158 struct btree            *btree_open_empty_copy(struct btree *bt);
159 int                      btree_clear(btree **bt);
160 int                      btree_replace(struct btree *bt, struct btree *btw);
161
162 static uint32_t
163 calculate_crc32(const char *begin, const char *end)
164 {
165         const uint32_t *begin32 = (const uint32_t*)begin;
166         const uint32_t *end32 = (const uint32_t*)(end - ((end - begin) % 4));
167         if (begin32 >= end32)
168                 return 0;
169         /* code derived from 32-bit CRC calculation by Gary S. Brown - Copyright (C) 1986. */
170         static const uint32_t crctable[256] = {
171                 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
172                 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
173                 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
174                 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
175                 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
176                 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
177                 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
178                 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
179                 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
180                 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
181                 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
182                 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
183                 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
184                 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
185                 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
186                 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
187                 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
188                 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
189                 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
190                 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
191                 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
192                 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
193                 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
194                 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
195                 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
196                 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
197                 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
198                 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
199                 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
200                 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
201                 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
202                 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
203         };
204
205         uint32_t crc = ~(*begin32++);
206         while (begin32 < end32) {
207                 begin = (const char*)begin32++;
208                 crc = (crc >> 8) ^ crctable[(crc ^ *(begin + 0)) & 0x000000ff];
209                 crc = (crc >> 8) ^ crctable[(crc ^ *(begin + 1)) & 0x000000ff];
210                 crc = (crc >> 8) ^ crctable[(crc ^ *(begin + 2)) & 0x000000ff];
211                 crc = (crc >> 8) ^ crctable[(crc ^ *(begin + 3)) & 0x000000ff];
212         }
213
214         // Hash up remaining bytes
215         if ((const char *)end32 < end) {
216                 begin = (const char *)end32;
217                 while (begin != end)
218                     crc = (crc >> 8) ^ crctable[(crc ^ *begin++) & 0x000000ff];
219         }
220
221         return ~crc;
222 }
223
224 static uint32_t
225 calculate_checksum(struct btree *bt, const struct page *p)
226 {
227         assert(p && bt);
228
229         const uint32_t       offset = offsetof(page, checksum) + sizeof(p->checksum);
230         const char          *begin = (const char *)p;
231         const char          *end = (const char *)p + bt->head.psize;
232
233         if (F_ISSET(bt->flags, BT_NOPGCHECKSUM))
234                 return 0;
235
236         DPRINTF("calculating checksum for page %u, flags %x", p->pgno, p->flags);
237
238         if (F_ISSET(p->flags, P_HEAD)) {
239                 return calculate_crc32(begin + offset, begin + PAGEHDRSZ + sizeof(struct bt_head));
240         } else if (F_ISSET(p->flags, P_META)) {
241                 return calculate_crc32(begin + offset, begin + PAGEHDRSZ + sizeof(struct bt_meta));
242         } else if (F_ISSET(p->flags, P_BRANCH) || F_ISSET(p->flags, P_LEAF)) {
243                 indx_t l = MAX(PAGEHDRSZ, p->lower);
244                 indx_t u = MIN(bt->head.psize, p->upper);
245                 if (l > u)
246                     l = u;
247                 uint32_t c1 = calculate_crc32(begin + offset, begin + l);
248                 uint32_t c2 = calculate_crc32(begin + u, end);
249                 return c1 ^ c2;
250         } else if (F_ISSET(p->flags, P_OVERFLOW)) {
251                 return calculate_crc32(begin + offset, end);
252         }
253
254         EPRINTF("unknown page type, flags = %x", p->flags);
255         return 0;
256 }
257
258 static int
259 verify_checksum(struct btree *bt, const struct page *p)
260 {
261         assert(bt && p);
262
263         uint32_t         c;
264
265         if (F_ISSET(bt->flags, BT_NOPGCHECKSUM))
266                 return BT_SUCCESS;
267
268         DPRINTF("verifying checksum for page %u", p->pgno);
269
270         c = calculate_checksum(bt, p);
271         if (c != p->checksum) {
272                 DPRINTF("checksum for page %u doesn't match: expected %x got %x", p->pgno, p->checksum, c);
273                 return BT_FAIL;
274         }
275         return BT_SUCCESS;
276 }
277
278 static int
279 memncmp(const void *s1, size_t n1, const void *s2, size_t n2, void *)
280 {
281         if (n1 < n2) {
282             int ret = memcmp(s1, s2, n1);
283                 if (ret == 0)
284                         return -1;
285                 else return ret;
286         }
287         else if (n1 > n2) {
288             int ret = memcmp(s1, s2, n2);
289                 if (ret == 0)
290                         return 1;
291                 else return ret;
292         }
293         return memcmp(s1, s2, n1);
294 }
295
296 static int
297 memnrcmp(const void *s1, size_t n1, const void *s2, size_t n2, void *)
298 {
299         const unsigned char     *p1;
300         const unsigned char     *p2;
301
302         if (n1 == 0)
303                 return n2 == 0 ? 0 : -1;
304
305         if (n2 == 0)
306                 return n1 == 0 ? 0 : 1;
307
308         p1 = (const unsigned char *)s1 + n1 - 1;
309         p2 = (const unsigned char *)s2 + n2 - 1;
310
311         while (*p1 == *p2) {
312                 if (p1 == s1)
313                         return (p2 == s2) ? 0 : -1;
314                 if (p2 == s2)
315                         return (p1 == p2) ? 0 : 1;
316                 p1--;
317                 p2--;
318         }
319         return *p1 - *p2;
320 }
321
322 void
323 btree_set_cmp(struct btree *bt, bt_cmp_func cmp, void *context)
324 {
325         bt->cmp = cmp;
326         bt->context = context;
327 }
328
329 int
330 btree_cmp(struct btree *bt, const struct btval *a, const struct btval *b)
331 {
332         return bt->cmp((const char *)a->data, a->size, (const char *)b->data, b->size, bt->context);
333 }
334
335 static void
336 common_prefix(struct btree *bt, struct btkey *min, struct btkey *max,
337     struct btkey *pfx)
338 {
339         size_t           n = 0;
340         char            *p1;
341         char            *p2;
342
343         if (min->len == 0 || max->len == 0 || bt->cmp) {
344                 pfx->len = 0;
345                 return;
346         }
347
348         if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
349                 p1 = min->str + min->len - 1;
350                 p2 = max->str + max->len - 1;
351
352                 while (*p1 == *p2) {
353                         p1--;
354                         p2--;
355                         n++;
356                         if (p1 < min->str || p2 < max->str)
357                                 break;
358                 }
359
360                 assert(n <= (int)sizeof(pfx->str));
361                 pfx->len = n;
362                 bcopy(p2 + 1, pfx->str, n);
363         } else {
364                 p1 = min->str;
365                 p2 = max->str;
366
367                 while (*p1 == *p2) {
368                         p1++;
369                         p2++;
370                         n++;
371                         if (n == min->len || n == max->len)
372                                 break;
373                 }
374
375                 assert(n <= (int)sizeof(pfx->str));
376                 pfx->len = n;
377                 bcopy(max->str, pfx->str, n);
378         }
379 }
380
381 static void
382 remove_prefix(struct btree *bt, struct btval *key, size_t pfxlen)
383 {
384         assert(bt);
385         if (pfxlen == 0 || bt->cmp != NULL)
386                 return;
387
388         DPRINTF("removing %zu bytes of prefix from key [%.*s]", pfxlen,
389             (int)key->size, (char *)key->data);
390         assert(pfxlen <= key->size);
391         key->size -= pfxlen;
392         if (!F_ISSET(bt->flags, BT_REVERSEKEY))
393                 key->data = (char *)key->data + pfxlen;
394 }
395
396 static void
397 expand_prefix(struct btree *bt, struct mpage *mp, indx_t indx,
398     struct btkey *expkey)
399 {
400         struct node     *node;
401         size_t           sz;
402
403         node = NODEPTR(mp, indx);
404         sz = (node->ksize + mp->prefix.len) > MAXPFXSIZE ? (MAXPFXSIZE - mp->prefix.len) : node->ksize;
405         expkey->len = sizeof(expkey->str);
406         concat_prefix(bt, mp->prefix.str, mp->prefix.len,
407             NODEKEY(node), sz, expkey->str, &expkey->len);
408 }
409
410 static int
411 bt_cmp(struct btree *bt, const struct btval *key1, const struct btval *key2,
412     struct btkey *pfx)
413 {
414         if (bt->cmp) {
415                 return bt->cmp((const char*)key1->data, key1->size, (const char*)key2->data, key2->size, bt->context);
416         } else {
417                 if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
418                         return memnrcmp(key1->data, key1->size - pfx->len,
419                                         key2->data, key2->size, 0);
420                 } else {
421                         return memncmp((char *)key1->data + pfx->len, key1->size - pfx->len,
422                                                 key2->data, key2->size, 0);
423
424                 }
425         }
426 }
427
428 void
429 btval_reset(struct btval *btv)
430 {
431         if (btv) {
432                 if (btv->mp)
433                         btv->mp->ref--;
434                 if (btv->free_data) {
435                         assert(btv->data);
436                         free(btv->data);
437                 }
438                 bzero(btv, sizeof(*btv));
439         }
440 }
441
442 int btval_ref(struct btval *btv)
443 {
444         assert(btv);
445         assert(btv->mp);
446         return ++btv->mp->ref;
447 }
448
449 int btval_deref(struct btval *btv)
450 {
451         assert(btv);
452         assert(btv->mp);
453         return --btv->mp->ref;
454 }
455
456 static int
457 mpage_cmp(struct mpage *a, struct mpage *b)
458 {
459         if (a->pgno > b->pgno)
460                 return 1;
461         if (a->pgno < b->pgno)
462                 return -1;
463         return 0;
464 }
465
466 static struct mpage *
467 mpage_lookup(struct btree *bt, pgno_t pgno)
468 {
469         struct mpage find;
470         struct mpage *mp = 0;
471
472         find.pgno = pgno;
473         mp = RB_FIND(page_cache, bt->page_cache, &find);
474         if (mp) {
475                 bt->stat.hits++;
476                 /* Update LRU queue. Move page to the end. */
477                 TAILQ_REMOVE(bt->lru_queue, mp, lru_next);
478                 TAILQ_INSERT_TAIL(bt->lru_queue, mp, lru_next);
479         }
480         return mp;
481 }
482
483 static void
484 mpage_add(struct btree *bt, struct mpage *mp)
485 {
486         assert(RB_INSERT(page_cache, bt->page_cache, mp) == NULL);
487         DPRINTF("mpage_add: mp=%p pgno=%d", mp, mp->pgno);
488         bt->stat.cache_size++;
489         TAILQ_INSERT_TAIL(bt->lru_queue, mp, lru_next);
490 }
491
492 static void
493 mpage_free(struct mpage *mp)
494 {
495         if (mp != NULL) {
496                 free(mp->page);
497                 free(mp);
498         }
499 }
500
501 static void
502 mpage_del(struct btree *bt, struct mpage *mp)
503 {
504         assert(RB_REMOVE(page_cache, bt->page_cache, mp) == mp);
505         DPRINTF("mpage_del: mp=%p pgno=%d", mp, mp->pgno);
506         assert(bt->stat.cache_size > 0);
507         bt->stat.cache_size--;
508         TAILQ_REMOVE(bt->lru_queue, mp, lru_next);
509 }
510
511 static void
512 mpage_flush(struct btree *bt)
513 {
514     struct mpage        *mp;
515
516     while ((mp = RB_MIN(page_cache, bt->page_cache)) != NULL) {
517             mpage_del(bt, mp);
518             mpage_free(mp);
519     }
520 }
521
522 static struct mpage *
523 mpage_copy(struct btree *bt, struct mpage *mp)
524 {
525         struct mpage    *copy;
526
527         if ((copy = (mpage *)calloc(1, sizeof(*copy))) == NULL)
528                 return NULL;
529         if ((copy->page = (page *)malloc(bt->head.psize)) == NULL) {
530                 free(copy);
531                 return NULL;
532         }
533         bcopy(mp->page, copy->page, bt->head.psize);
534         bcopy(&mp->prefix, &copy->prefix, sizeof(mp->prefix));
535         copy->parent = mp->parent;
536         copy->parent_index = mp->parent_index;
537         copy->pgno = mp->pgno;
538
539         return copy;
540 }
541
542 /* Remove the least recently used memory pages until the cache size is
543  * within the configured bounds. Pages referenced by cursors or returned
544  * key/data are not pruned.
545  */
546 static void
547 mpage_prune(struct btree *bt)
548 {
549         struct mpage    *mp, *next;
550
551         for (mp = TAILQ_FIRST(bt->lru_queue); mp; mp = next) {
552                 if (bt->stat.cache_size <= bt->stat.max_cache)
553                         break;
554                 next = TAILQ_NEXT(mp, lru_next);
555                 if (!mp->dirty && mp->ref <= 0) {
556                         mpage_del(bt, mp);
557                         mpage_free(mp);
558                 }
559         }
560 }
561
562 /* Mark a page as dirty and push it on the dirty queue.
563  */
564 static void
565 mpage_dirty(struct btree *bt, struct mpage *mp)
566 {
567         assert(bt != NULL);
568         assert(bt->txn != NULL);
569
570         if (!mp->dirty) {
571                 mp->dirty = 1;
572                 SIMPLEQ_INSERT_TAIL(bt->txn->dirty_queue, mp, next);
573         }
574 }
575
576 /* Touch a page: make it dirty and re-insert into tree with updated pgno.
577  */
578 static struct mpage *
579 mpage_touch(struct btree *bt, struct mpage *mp)
580 {
581         assert(bt != NULL);
582         assert(bt->txn != NULL);
583         assert(mp != NULL);
584
585         if (!mp->dirty) {
586                 DPRINTF("touching page %u -> %u", mp->pgno, bt->txn->next_pgno);
587                 if (mp->ref == 0)
588                         mpage_del(bt, mp);
589                 else {
590                         if ((mp = mpage_copy(bt, mp)) == NULL)
591                                 return NULL;
592                 }
593                 mp->pgno = mp->page->pgno = bt->txn->next_pgno++;
594                 mpage_dirty(bt, mp);
595                 mpage_add(bt, mp);
596
597                 /* Update the page number to new touched page. */
598                 if (mp->parent != NULL)
599                         NODEPGNO(NODEPTR(mp->parent,
600                             mp->parent_index)) = mp->pgno;
601         }
602
603         return mp;
604 }
605
606 static int
607 btree_read_page(struct btree *bt, pgno_t pgno, struct page *page)
608 {
609         ssize_t          rc;
610
611         DPRINTF("reading page %u", pgno);
612         bt->stat.reads++;
613         if ((rc = pread(bt->fd, page, bt->head.psize, (off_t)pgno*bt->head.psize)) == 0) {
614                 DPRINTF("page %u doesn't exist", pgno);
615                 errno = ENOENT;
616                 return BT_FAIL;
617         } else if (rc != (ssize_t)bt->head.psize) {
618                 if (rc > 0)
619                         errno = EINVAL;
620                 fprintf(stderr, "%s:%d: short pread rc=%zd psize=%d\n",
621                         __FUNCTION__, __LINE__, rc, bt->head.psize);
622                 DPRINTF("read: %s", strerror(errno));
623                 return BT_FAIL;
624         }
625
626         if (page->pgno != pgno) {
627                 EPRINTF("page numbers don't match: %u != %u", pgno, page->pgno);
628                 errno = EINVAL;
629                 return BT_FAIL;
630         }
631
632         if (verify_checksum(bt, page) != 0) {
633                 EPRINTF("checksum error for page %d", pgno);
634                 errno = EINVAL;
635                 return BT_FAIL;
636         }
637
638         DPRINTF("page %u has flags 0x%X", pgno, page->flags);
639
640         return BT_SUCCESS;
641 }
642
643 int
644 btree_sync(struct btree *bt)
645 {
646         unsigned int         flags = BT_MARKER;
647         if (!F_ISSET(bt->flags, BT_NOSYNC))
648                 return fsync(bt->fd);
649         if (F_ISSET(bt->flags, BT_USEMARKER) && !F_ISSET(bt->meta.flags, BT_MARKER)) {
650             /* If we're closing a dead btree then add the tombstone flag */
651             if (F_ISSET(bt->meta.flags, BT_TOMBSTONE))
652                     flags |= BT_TOMBSTONE;
653             /* we want to use marker and the last meta page doesn't have it */
654             /* put a copy of the last meta page but this time with a marker */
655             if (bt->txn) {
656                 EPRINTF("btree_sync while in transaction is not a good idea");
657                 return BT_FAIL;
658             }
659             if (fsync(bt->fd) != 0)
660                     return BT_FAIL;
661             bt->txn = btree_txn_begin(bt, 0);
662             if (bt->txn == 0)
663                     return BT_FAIL;
664             if (btree_write_meta(bt, bt->meta.root, flags, bt->meta.tag) == BT_FAIL) {
665                     btree_txn_abort(bt->txn);
666                     return BT_FAIL;
667             }
668             btree_txn_abort(bt->txn);
669             return BT_SUCCESS;
670         }
671         return 0;
672 }
673
674
675 struct btree_txn *
676 btree_txn_begin(struct btree *bt, int rdonly)
677 {
678         struct btree_txn        *txn;
679
680         if (!rdonly && bt->txn != NULL) {
681                 DPRINTF("write transaction already begun");
682                 errno = EBUSY;
683                 return NULL;
684         }
685
686         if ((txn = (btree_txn *)calloc(1, sizeof(*txn))) == NULL) {
687                 DPRINTF("calloc: %s", strerror(errno));
688                 return NULL;
689         }
690
691         if (rdonly) {
692                 txn->flags |= BT_TXN_RDONLY;                
693                 DPRINTF("taking read lock on txn %p, bt %p", txn, bt);
694         } else {
695                 txn->dirty_queue = (dirty_queue *)calloc(1, sizeof(*txn->dirty_queue));
696                 if (txn->dirty_queue == NULL) {
697                         free(txn);
698                         return NULL;
699                 }
700                 SIMPLEQ_INIT(txn->dirty_queue);
701
702                 DPRINTF("taking write lock on txn %p, bt %p", txn, bt);
703                 if (flock(bt->fd, LOCK_EX | LOCK_NB) != 0) {
704                         EPRINTF("flock: %s", strerror(errno));
705                         errno = EBUSY;
706                         free(txn->dirty_queue);
707                         free(txn);
708                         return NULL;
709                 }
710                 bt->txn = txn;
711         }
712
713         txn->bt = bt;
714         btree_ref(bt);
715
716         if (btree_read_meta(bt, &txn->next_pgno) != BT_SUCCESS) {
717                 btree_txn_abort(txn);
718                 return NULL;
719         }
720
721         txn->root = bt->meta.root;
722         txn->tag = bt->meta.tag;
723         DPRINTF("begin transaction on btree %p, root page %u (tag %d)", bt, txn->root, txn->tag);
724
725         return txn;
726 }
727
728 struct btree_txn *
729 btree_txn_begin_with_tag(struct btree *bt, unsigned int tag)
730 {
731     struct btree_txn *txn;
732     pgno_t root_page;
733
734     if (btree_read_meta_with_tag(bt, tag, &root_page) != BT_SUCCESS) {
735             return NULL;
736     }
737
738     if ((txn = (btree_txn *)calloc(1, sizeof(*txn))) == NULL) {
739             DPRINTF("calloc: %s", strerror(errno));
740             return NULL;
741     }
742
743     txn->root  = root_page;
744     txn->bt    = bt;
745     txn->flags = BT_TXN_RDONLY;
746     txn->tag   = tag;
747     btree_ref(bt);
748
749     DPRINTF("begin transaction on btree %p, root page %u (tag %d)", bt, txn->root, txn->tag);
750
751     return txn;
752 }
753
754 void
755 btree_txn_abort(struct btree_txn *txn)
756 {
757         struct mpage    *mp;
758         struct btree    *bt;
759
760         if (txn == NULL)
761                 return;
762
763         bt = txn->bt;
764         DPRINTF("abort transaction on btree %p, root page %u", bt, txn->root);
765
766         if (!F_ISSET(txn->flags, BT_TXN_RDONLY)) {
767                 /* Discard all dirty pages.
768                  */
769                 while (!SIMPLEQ_EMPTY(txn->dirty_queue)) {
770                         mp = SIMPLEQ_FIRST(txn->dirty_queue);
771                         assert(mp->ref == 0);   /* cursors should be closed */
772                         mpage_del(bt, mp);
773                         SIMPLEQ_REMOVE_HEAD(txn->dirty_queue, next);
774                         mpage_free(mp);
775                 }
776
777                 DPRINTF("releasing write lock on txn %p", txn);
778                 txn->bt->txn = NULL;
779                 if (flock(txn->bt->fd, LOCK_UN) != 0) {
780                         DPRINTF("failed to unlock fd %d: %s",
781                             txn->bt->fd, strerror(errno));
782                 }
783                 free(txn->dirty_queue);
784         }
785
786         btree_close(txn->bt);
787         free(txn);
788 }
789
790 int
791 btree_txn_is_read(struct btree_txn *txn)
792 {
793         assert(txn);
794         return txn->flags & BT_TXN_RDONLY ? 1 : 0;
795 }
796
797 int
798 btree_txn_is_error(struct btree_txn *txn)
799 {
800         assert(txn);
801         return txn->flags & BT_TXN_ERROR ? 1 : 0;
802 }
803
804 unsigned int
805 btree_txn_get_tag(struct btree_txn *txn)
806 {
807     assert(txn != 0);
808     return txn->tag;
809 }
810
811 int
812 btree_txn_commit(struct btree_txn *txn, unsigned int tag, unsigned int flags)
813 {
814         int              n, done;
815         ssize_t          rc;
816         off_t            size;
817         struct mpage    *mp;
818         struct btree    *bt;
819         struct iovec     iov[BT_COMMIT_PAGES];
820         const int        needfsync = !F_ISSET(txn->bt->flags, BT_NOSYNC) || F_ISSET(flags, BT_FORCE_MARKER);
821         unsigned long    num_dirty = 0;
822         unsigned long    num_dirty_branches = 0;
823         unsigned long    num_dirty_leaves = 0;
824         unsigned long    num_dirty_overflows = 0;
825
826         assert(txn != NULL);
827         assert(txn->bt != NULL);
828
829         bt = txn->bt;
830
831         if (F_ISSET(txn->flags, BT_TXN_RDONLY)) {
832                 DPRINTF("attempt to commit read-only transaction");
833                 btree_txn_abort(txn);
834                 errno = EPERM;
835                 return BT_FAIL;
836         }
837
838         if (txn != bt->txn) {
839                 EPRINTF("attempt to commit unknown transaction");
840                 btree_txn_abort(txn);
841                 errno = EINVAL;
842                 return BT_FAIL;
843         }
844
845         if (F_ISSET(txn->flags, BT_TXN_ERROR)) {
846                 EPRINTF("error flag is set, can't commit");
847                 btree_txn_abort(txn);
848                 errno = EINVAL;
849                 return BT_FAIL;
850         }
851
852         if (SIMPLEQ_EMPTY(txn->dirty_queue)) {
853                 if (bt->stat.tag != tag) {
854                         goto done;
855                 } else {
856                         mpage_prune(bt);
857                         btree_txn_abort(txn);
858                         return BT_SUCCESS;
859                 }
860         }
861
862         if (F_ISSET(bt->flags, BT_FIXPADDING)) {
863                 size = lseek(bt->fd, 0, SEEK_END);
864                 size += bt->head.psize - (size % bt->head.psize);
865                 DPRINTF("extending to multiple of page size: %llu", (long long unsigned)size);
866                 if (ftruncate(bt->fd, size) != 0) {
867                         DPRINTF("ftruncate: %s", strerror(errno));
868                         btree_txn_abort(txn);
869                         return BT_FAIL;
870                 }
871                 bt->flags &= ~BT_FIXPADDING;
872         }
873
874         DPRINTF("committing transaction on btree %p, root page %u",
875             bt, txn->root);
876
877         /* Commit up to BT_COMMIT_PAGES dirty pages to disk until done.
878          */
879         do {
880                 n = 0;
881                 done = 1;
882                 SIMPLEQ_FOREACH(mp, txn->dirty_queue, next) {
883                         mp->page->checksum = calculate_checksum(bt, mp->page);
884                         iov[n].iov_len = bt->head.psize;
885                         iov[n].iov_base = mp->page;
886                         if (IS_BRANCH(mp))
887                                 num_dirty_branches++;
888                         else if (IS_LEAF(mp))
889                                 num_dirty_leaves++;
890                         else
891                                 num_dirty_overflows++;
892                         DPRINTF("commiting page %u == %u with checksum %x", mp->pgno, mp->page->pgno, mp->page->checksum);
893                         if (++n >= BT_COMMIT_PAGES) {
894                                 done = 0;
895                                 break;
896                         }
897                 }
898
899                 if (n == 0)
900                         break;
901
902                 num_dirty += n;
903
904                 DPRINTF("commiting %u dirty pages", n);
905                 bt->stat.writes += n;
906                 rc = writev(bt->fd, iov, n);
907                 if (rc != (ssize_t)bt->head.psize*n) {
908                         if (rc > 0) {
909                                 DPRINTF("short write, filesystem full?");
910                         } else {
911                                 DPRINTF("writev: %s", strerror(errno));
912                         }
913                         btree_txn_abort(txn);
914                         return BT_FAIL;
915                 }
916
917                 /* Remove the dirty flag from the written pages.
918                  */
919                 while (!SIMPLEQ_EMPTY(txn->dirty_queue)) {
920                         mp = SIMPLEQ_FIRST(txn->dirty_queue);
921                         mp->dirty = 0;
922                         SIMPLEQ_REMOVE_HEAD(txn->dirty_queue, next);
923                         if (--n == 0)
924                                 break;
925                 }
926         } while (!done);
927         if (num_dirty > bt->stat.max_cache) {
928                 fprintf(stderr, "large transaction: \t %ld B %ld L %ld O dirty \t %d B %d L %d O live pages %s\n",
929                         num_dirty_branches, num_dirty_leaves, num_dirty_overflows,
930                         bt->meta.branch_pages, bt->meta.leaf_pages, bt->meta.overflow_pages,
931                         bt->path);
932         }
933 done:
934         if (needfsync) {
935                 if (fsync(bt->fd) != 0) {
936                         btree_txn_abort(txn);
937                         return BT_FAIL;
938                 }
939         }
940         if (btree_write_meta(bt, txn->root,
941                              needfsync ? BT_MARKER : 0,
942                              tag) != BT_SUCCESS) {
943                 btree_txn_abort(txn);
944                 return BT_FAIL;
945         }
946
947         mpage_prune(bt);
948         btree_txn_abort(txn);
949
950         return BT_SUCCESS;
951 }
952
953 static int
954 btree_write_header(struct btree *bt, int fd)
955 {
956         struct stat      sb;
957         struct bt_head  *h;
958         struct page     *p;
959         ssize_t          rc;
960         unsigned int     psize;
961
962         DPRINTF("writing header page");
963         assert(bt != NULL);
964
965         /* Ask stat for optimal blocksize for I/O but
966            don't use smaller than the initial page size */
967         psize = PAGESIZE;
968         if (fstat(fd, &sb) == 0 && sb.st_blksize > PAGESIZE)
969             psize = sb.st_blksize;
970
971         if ((p = (page *)calloc(1, psize)) == NULL)
972                 return -1;
973         p->flags = P_HEAD;
974
975         h = (bt_head *)METADATA(p);
976         h->magic = BT_MAGIC;
977         h->version = BT_VERSION;
978         h->psize = psize;
979         h->ksize = MAXKEYSIZE;
980         bcopy(h, &bt->head, sizeof(*h));
981
982         p->checksum = calculate_checksum(bt, p);
983         DPRINTF("writing page %u with checksum %x", p->pgno, p->checksum);
984         bt->stat.writes++;
985         rc = write(fd, p, bt->head.psize);
986         free(p);
987         if (rc != (ssize_t)bt->head.psize) {
988                 if (rc > 0)
989                         DPRINTF("short write, filesystem full?");
990                 return BT_FAIL;
991         }
992
993         return BT_SUCCESS;
994 }
995
996 static int
997 btree_read_header(struct btree *bt)
998 {
999         char             page[PAGESIZE];
1000         struct page     *p = 0;
1001         struct page     *pcheck = 0;
1002         struct bt_head  *h = 0;
1003         ssize_t          rc;
1004         assert(bt != NULL);
1005
1006         /* We don't know the page size yet, so use a minimum value.
1007          */
1008
1009         bt->stat.reads++;
1010         if ((rc = pread(bt->fd, page, PAGESIZE, 0)) == 0) {
1011                 errno = ENOENT;
1012                 goto fail;
1013         } else if ((size_t)rc != PAGESIZE) {
1014                 EPRINTF("read: %s", strerror(errno));
1015                 if (rc > 0)
1016                         errno = EINVAL;
1017                 goto fail;
1018         }
1019
1020         p = (struct page *)page;
1021
1022         if (!F_ISSET(p->flags, P_HEAD)) {
1023                 EPRINTF("page %d not a header page", p->pgno);
1024                 errno = EINVAL;
1025                 goto fail;
1026         }
1027
1028         h = (bt_head *)METADATA(p);
1029         if (h->magic != BT_MAGIC) {
1030                 EPRINTF("header has invalid magic");
1031                 errno = EINVAL;
1032                 goto fail;
1033         }
1034
1035         if (h->version != BT_VERSION) {
1036                 EPRINTF("database is version %u, expected version %u",
1037                     bt->head.version, BT_VERSION);
1038                 errno = EINVAL;
1039                 goto fail;
1040         }
1041
1042         if (h->ksize != MAXKEYSIZE) {
1043                 EPRINTF("database uses max key size %u, expected max key size %u",
1044                     bt->head.ksize, MAXKEYSIZE);
1045                 errno = EINVAL;
1046                 goto fail;
1047         }
1048
1049         bcopy(h, &bt->head, sizeof(*h));
1050
1051         if (bt->head.psize == PAGESIZE) {
1052                 pcheck = p;
1053         } else {
1054                 const size_t pheadsz = PAGEHDRSZ + sizeof(bt_head);
1055                 pcheck = (struct page *)malloc(pheadsz);
1056                 bt->stat.reads++;
1057                 if (pread(bt->fd, page, pheadsz, 0) <= 0) {
1058                     EPRINTF("pread failed to get data to verify checksum");
1059                     goto fail;
1060                 }
1061         }
1062
1063         if (verify_checksum(bt, pcheck) != 0) {
1064                 EPRINTF("checksum fail");
1065                 goto fail;
1066         } else {
1067                 if (pcheck != p)
1068                     free(pcheck);
1069         }
1070
1071         DPRINTF("btree_read_header: magic = %x", bt->head.magic);
1072         DPRINTF("btree_read_header: version = %d", bt->head.version);
1073         DPRINTF("btree_read_header: flags = %d", bt->head.flags);
1074         DPRINTF("btree_read_header: psize = %d", bt->head.psize);
1075         DPRINTF("btree_read_header: ksize = %d", bt->head.ksize);
1076
1077         return 0;
1078 fail:
1079         if (pcheck && pcheck != p)
1080             free(pcheck);
1081         return -1;
1082 }
1083
1084 static int
1085 btree_write_meta(struct btree *bt, pgno_t root, unsigned int flags, uint32_t tag)
1086 {
1087         struct mpage    *mp, *prev_mp;
1088         struct bt_meta  *meta;
1089         ssize_t          rc;
1090
1091         DPRINTF("writing meta page for root page %u with flags %d and tag %d", root, flags, tag);
1092
1093         assert(bt != NULL);
1094         assert(bt->txn != NULL);
1095
1096         if ((mp = btree_new_page(bt, P_META)) == NULL)
1097                 return -1;
1098
1099         // get prev meta mpage from cache
1100         prev_mp = mpage_lookup(bt, bt->meta.pgno);
1101
1102         bt->meta.prev_meta = bt->meta.pgno;
1103         bt->meta.pgno = mp->pgno;
1104         bt->meta.root = root;
1105         bt->meta.flags = flags;
1106         bt->meta.created_at = time(0);
1107         bt->meta.revisions++;
1108         bt->meta.tag = tag;
1109
1110         if (F_ISSET(bt->flags, BT_NOPGCHECKSUM)) {
1111                 bt->hasher->reset();
1112                 bt->hasher->addData((const char *)&bt->meta, METAHASHLEN);
1113                 QByteArray result = bt->hasher->result();
1114                 memcpy(bt->meta.hash, result.constData(), result.size());
1115         }
1116
1117         /* Copy the meta data changes to the new meta page. */
1118         meta = METADATA(mp->page);
1119         bcopy(&bt->meta, meta, sizeof(*meta));
1120
1121         mp->page->checksum = calculate_checksum(bt, mp->page);
1122         DPRINTF("writing page %u with checksum %x, digest %.*s", mp->page->pgno, mp->page->checksum, SHA_DIGEST_LENGTH, meta->hash);
1123
1124         bt->stat.writes++;
1125         rc = write(bt->fd, mp->page, bt->head.psize);
1126         mp->dirty = 0;
1127         SIMPLEQ_REMOVE_HEAD(bt->txn->dirty_queue, next);
1128         if (prev_mp) {
1129                 mpage_del(bt, prev_mp);
1130                 mpage_free(prev_mp);
1131         }
1132         if (rc != (ssize_t)bt->head.psize) {
1133                 if (rc > 0)
1134                         DPRINTF("short write, filesystem full?");
1135                 return BT_FAIL;
1136         }
1137
1138         if ((bt->size = lseek(bt->fd, 0, SEEK_END)) == -1) {
1139                 DPRINTF("failed to update file size: %s", strerror(errno));
1140                 bt->size = 0;
1141         }
1142         return BT_SUCCESS;
1143 }
1144
1145 /* Returns true if page p is a valid meta page, false otherwise.
1146  */
1147 static int
1148 btree_is_meta_page(struct btree *bt, struct page *p)
1149 {
1150         struct bt_meta  *m;
1151         unsigned char    hash[SHA_DIGEST_LENGTH];
1152
1153         m = METADATA(p);
1154         if (!F_ISSET(p->flags, P_META)) {
1155                 DPRINTF("page %d not a meta page", p->pgno);
1156                 errno = EINVAL;
1157                 return 0;
1158         }
1159
1160         if (m->root >= p->pgno && m->root != P_INVALID) {
1161                 EPRINTF("page %d points to an invalid root page", p->pgno);
1162                 errno = EINVAL;
1163                 return 0;
1164         }
1165
1166         if (F_ISSET(bt->flags, BT_NOPGCHECKSUM)) {
1167                 bt->hasher->reset();
1168                 bt->hasher->addData((const char *)m, METAHASHLEN);
1169                 QByteArray result = bt->hasher->result();
1170                 memcpy(hash, result.constData(), result.size());
1171
1172                 if (bcmp(hash, m->hash, SHA_DIGEST_LENGTH) != 0) {
1173                         EPRINTF("page %d has an invalid digest %.*s", p->pgno, SHA_DIGEST_LENGTH, m->hash);
1174                         errno = EINVAL;
1175                         return 0;
1176                 }
1177         }
1178
1179         return 1;
1180 }
1181
1182 static int
1183 btree_read_meta(struct btree *bt, pgno_t *p_next)
1184 {
1185         struct mpage    *mp;
1186         struct bt_meta  *meta;
1187         pgno_t           meta_pgno, next_pgno, rest_pgno;
1188         off_t            size;
1189         off_t            bt_prev_sz = bt->size;
1190
1191         assert(bt != NULL);
1192
1193         if ((size = lseek(bt->fd, 0, SEEK_END)) == -1) {
1194                 fprintf(stderr, "failed to lseek errno=%d\n", errno);
1195                 goto fail;
1196         }
1197
1198         DPRINTF("btree_read_meta: size = %llu", (long long unsigned)size);
1199
1200         if (size < bt->size) {
1201                 EPRINTF("file has shrunk!");
1202                 errno = EIO;
1203                 goto fail;
1204         }
1205
1206         if ((uint32_t)size == bt->head.psize) {           /* there is only the header */
1207                 if (p_next != NULL)
1208                         *p_next = 1;
1209                 return BT_SUCCESS;              /* new file */
1210         }
1211
1212         next_pgno = size / bt->head.psize;
1213         if (next_pgno == 0) {
1214                 DPRINTF("corrupt file");
1215                 fprintf(stderr, "corrupt file\n");
1216                 errno = EIO;
1217                 goto fail;
1218         }
1219
1220         meta_pgno = next_pgno - 1;
1221
1222         if (size % bt->head.psize != 0) {
1223                 DPRINTF("filesize not a multiple of the page size!");
1224                 bt->flags |= BT_FIXPADDING;
1225                 next_pgno++;
1226         }
1227
1228         if (p_next != NULL)
1229                 *p_next = next_pgno;
1230
1231         if (size == bt->size) {
1232                 DPRINTF("size unchanged, keeping current meta page");
1233                 if (F_ISSET(bt->meta.flags, BT_TOMBSTONE)) {
1234                         DPRINTF("file is dead");
1235                         errno = ESTALE;
1236                         return BT_FAIL;
1237                 } else
1238                         return BT_SUCCESS;
1239         }
1240         bt->size = size;
1241
1242         while (meta_pgno > 0) {
1243                 mp = btree_get_mpage(bt, meta_pgno); // TODO: Add page type to get_mpage, early out (avoid checksum checks)
1244                 if (mp && btree_is_meta_page(bt, mp->page)) {
1245                         meta = METADATA(mp->page);
1246                         DPRINTF("flags = 0x%x", meta->flags);
1247                         if (F_ISSET(meta->flags, BT_TOMBSTONE)) {
1248                                 DPRINTF("file is dead");
1249                                 errno = ESTALE;
1250                                 return BT_FAIL;
1251                         } else if (F_ISSET(bt->flags, BT_USEMARKER) && !F_ISSET(meta->flags, BT_MARKER)) {
1252                                 DPRINTF("found a meta page %d but without marker, skipping...", meta_pgno);
1253                                 /* dont skip if pages up to last marked meta are ok */
1254                                 if (!F_ISSET(bt->flags, BT_NOPGCHECKSUM)) {
1255                                         rest_pgno = meta_pgno - 1;
1256                                         while ((mp = btree_get_mpage(bt, rest_pgno)) != NULL) {
1257                                                 if (rest_pgno == 0 || (btree_is_meta_page(bt, mp->page) && F_ISSET(METADATA(mp->page)->flags, BT_MARKER))) {
1258                                                         bcopy(meta, &bt->meta, sizeof(bt->meta));
1259                                                         return BT_SUCCESS;
1260                                                 }
1261                                                 rest_pgno--;
1262                                                 if (mp) {
1263                                                         mpage_del(bt, mp);
1264                                                         mpage_free(mp);
1265                                                         mp = 0;
1266                                                 }
1267                                         }
1268                                 }
1269                         } else {
1270                                 /* Make copy of last meta page. */
1271                                 bcopy(meta, &bt->meta, sizeof(bt->meta));
1272                                 return BT_SUCCESS;
1273                         }
1274                 }
1275                 if (mp) {
1276                         mpage_del(bt, mp);
1277                         mpage_free(mp);
1278                 }
1279                 --meta_pgno;    /* scan backwards to first valid meta page */
1280         }
1281
1282         errno = EIO;
1283         if (bt_prev_sz)
1284                 EPRINTF("failed somehow errno=%d\n", errno);
1285 fail:
1286         if (p_next != NULL)
1287                 *p_next = P_INVALID;
1288         return BT_FAIL;
1289 }
1290
1291 static int
1292 btree_read_meta_with_tag(struct btree *bt, unsigned int tag, pgno_t *p_root)
1293 {
1294         pgno_t pgno;
1295         struct page *p;
1296         struct bt_meta *meta;
1297
1298         assert(bt != NULL);
1299         assert(p_root != NULL);
1300
1301         if (btree_read_meta(bt, NULL) != BT_SUCCESS)
1302             return BT_FAIL;
1303
1304         if (bt->meta.tag == tag) {
1305                 *p_root = bt->meta.root;
1306                 return BT_SUCCESS;
1307         }
1308
1309         if ((p = (page *)malloc(bt->head.psize)) == NULL) {
1310                 free(p);
1311                 return BT_FAIL;
1312         }
1313
1314         pgno = bt->meta.prev_meta;
1315         while (pgno != P_INVALID) {
1316                 if (btree_read_page(bt, pgno, p) != BT_SUCCESS) {
1317                         free(p);
1318                         return BT_FAIL;
1319                 }
1320                 if (!F_ISSET(p->flags, P_META)) {
1321                         EPRINTF("corrupted meta page chain detected (page %d flags %d)", pgno, p->flags);
1322                         free(p);
1323                         return BT_FAIL;
1324                 }
1325                 if (!btree_is_meta_page(bt, p)) {
1326                         EPRINTF("corrupted meta page found (page %d flags %d)", pgno, p->flags);
1327                         free(p);
1328                         return BT_FAIL;
1329                 }
1330                 meta = METADATA(p);
1331                 if (meta->tag == tag) {
1332                         *p_root = meta->root;
1333                         free(p);
1334                         return BT_SUCCESS;
1335                 }
1336                 pgno = meta->prev_meta;
1337         }
1338         free(p);
1339         return BT_FAIL;
1340 }
1341
1342 struct btree *
1343 btree_open_fd(const char *path, int fd, unsigned int flags)
1344 {
1345         struct btree    *bt;
1346         int              fl;
1347
1348         fl = fcntl(fd, F_GETFL, 0);
1349         int rc;
1350         if ((rc = fcntl(fd, F_SETFL, fl | O_APPEND)) == -1) {
1351                 EPRINTF( "fcntl fd=%d rc=%d errno=%d\n", fd, rc, errno);
1352                 return NULL;
1353         }
1354
1355         bt = (struct btree *)calloc(1, sizeof(btree));
1356         // initialize the hasher
1357         bt->hasher = new QCryptographicHash(QCryptographicHash::Sha1);
1358
1359         if (!bt) {
1360             EPRINTF("failed to allocate memory for btree");
1361             goto fail;
1362         }
1363
1364         bt->fd = fd;
1365         bt->flags = flags;
1366         bt->flags &= ~BT_FIXPADDING;
1367         bt->ref = 1;
1368         bt->meta.pgno = P_INVALID;
1369         bt->meta.root = P_INVALID;
1370         bt->meta.prev_meta = P_INVALID;
1371         bt->path = (char*)malloc(strlen(path) + 1);
1372         strcpy(bt->path, path);
1373
1374         if ((bt->page_cache = (struct page_cache *)calloc(1, sizeof(*bt->page_cache))) == NULL)
1375               goto fail;
1376         bt->stat.max_cache = BT_MAXCACHE_DEF;
1377         RB_INIT(bt->page_cache);
1378
1379         if ((bt->lru_queue = (lru_queue *)calloc(1, sizeof(*bt->lru_queue))) == NULL) {
1380                 EPRINTF("failed to allocate lru_queue");
1381                 goto fail;
1382         }
1383         TAILQ_INIT(bt->lru_queue);
1384
1385         if (btree_read_header(bt) != 0) {
1386                 if (errno != ENOENT) {
1387                         EPRINTF("failed to read header");
1388                         goto fail;
1389                 }
1390                 DPRINTF("new database");
1391                 btree_write_header(bt, bt->fd);
1392         }
1393
1394         if (btree_read_meta(bt, NULL) != 0) {
1395                 DPRINTF("valid meta not found. Clearing file");
1396                 if (F_ISSET(bt->flags, BT_RDONLY) || btree_clear(&bt) != BT_SUCCESS) {
1397                         EPRINTF("failed to read meta");
1398                         goto fail;
1399                 }
1400         }
1401
1402         DPRINTF("opened database version %u, pagesize %u",
1403             bt->head.version, bt->head.psize);
1404         DPRINTF("timestamp: %s", ctime((const time_t *)&bt->meta.created_at));
1405         DPRINTF("depth: %u", bt->meta.depth);
1406         DPRINTF("entries: %llu", (long long unsigned)bt->meta.entries);
1407         DPRINTF("revisions: %u", bt->meta.revisions);
1408         DPRINTF("branch pages: %u", bt->meta.branch_pages);
1409         DPRINTF("leaf pages: %u", bt->meta.leaf_pages);
1410         DPRINTF("overflow pages: %u", bt->meta.overflow_pages);
1411         DPRINTF("root: %u", bt->meta.root);
1412         DPRINTF("previous meta page: %u", bt->meta.prev_meta);
1413
1414         return bt;
1415
1416 fail:
1417         EPRINTF("%s: fail errno=%d\n", path, errno);
1418         if (bt) {
1419             free(bt->lru_queue);
1420             free(bt->page_cache);
1421             free(bt->path);
1422         }
1423         free(bt);
1424         return NULL;
1425 }
1426
1427 int
1428 btree_clear(btree **bt)
1429 {
1430         struct btree *btc;
1431
1432         assert(bt && *bt);
1433
1434         btc = btree_open_empty_copy(*bt);
1435
1436         if (!btc) {
1437                 EPRINTF("failed to open new file");
1438                 return BT_FAIL;
1439         }
1440
1441         if (btree_replace(*bt, btc) != BT_SUCCESS) {
1442                 EPRINTF("failed to replace");
1443                 return BT_FAIL;
1444         }
1445
1446         strcpy(btc->path, (*bt)->path);
1447         btree_close(*bt);
1448         *bt = btc;
1449         return BT_SUCCESS;
1450 }
1451
1452 int
1453 btree_replace(btree *bt, btree *btw)
1454 {
1455         struct btree_txn *txn;
1456
1457         assert(bt && btw);
1458
1459         if ((txn = btree_txn_begin(bt, 0)) == NULL)
1460                 return BT_FAIL;
1461
1462         DPRINTF("replacing %s with %s", bt->path, btw->path);
1463         if (rename(btw->path, bt->path) != 0)
1464                 goto fail;
1465
1466         /* Write a "tombstone" meta page so other processes can pick up
1467          * the change and re-open the file.
1468          */
1469         if (btree_write_meta(bt, P_INVALID, BT_TOMBSTONE, 0) != BT_SUCCESS)
1470                 goto fail;
1471
1472         btree_txn_abort(txn);
1473         return BT_SUCCESS;
1474 fail:
1475         btree_txn_abort(txn);
1476         return BT_FAIL;
1477 }
1478
1479 struct btree*
1480 btree_open_empty_copy(struct btree *bt)
1481 {
1482         char                    *copy_path = NULL;
1483         const char               copy_ext[] = ".copy.XXXXXX";
1484         struct btree            *btc;
1485         int                      fd;
1486
1487         assert(bt != NULL);
1488
1489         DPRINTF("creating empty copy of btree %p with path %s", bt, bt->path);
1490
1491         if (bt->path == NULL) {
1492                 errno = EINVAL;
1493                 return 0;
1494         }
1495
1496         copy_path = (char*)malloc(strlen(bt->path) + strlen(copy_ext) + 1);
1497         strcpy(copy_path, bt->path);
1498         strcat(copy_path, copy_ext);
1499
1500         fd = mkstemp(copy_path);
1501         if (fd == -1) {
1502                 EPRINTF("failed to get fd for empty copy");
1503                 goto failed;
1504         }
1505
1506         if ((btc = btree_open_fd(copy_path, fd, bt->flags)) == NULL)
1507                 goto failed;
1508         DPRINTF("opened empty btree %p", btc);
1509
1510         free(copy_path);
1511         return btc;
1512
1513 failed:
1514         unlink(copy_path);
1515         free(copy_path);
1516         btree_close(btc);
1517         return 0;
1518 }
1519
1520
1521 struct btree *
1522 btree_open(const char *path, unsigned int flags, mode_t mode)
1523 {
1524         int              fd, oflags;
1525         struct btree    *bt;
1526
1527         if (F_ISSET(flags, BT_RDONLY))
1528                 oflags = O_RDONLY;
1529         else
1530                 oflags = O_RDWR | O_CREAT | O_APPEND;
1531
1532         fd = open(path, oflags, mode);
1533         if (fd == -1)
1534                 return NULL;
1535         if ((bt = btree_open_fd(path, fd, flags)) == NULL)
1536                 close(fd);
1537         else {
1538                 DPRINTF("opened btree %p", bt);
1539         }
1540
1541         return bt;
1542 }
1543
1544 int btree_get_fd(struct btree *bt)
1545 {
1546         return bt->fd;
1547 }
1548
1549 static void
1550 btree_ref(struct btree *bt)
1551 {
1552         bt->ref++;
1553         DPRINTF("ref is now %d on btree %p", bt->ref, bt);
1554 }
1555
1556 void
1557 btree_close(struct btree *bt)
1558 {
1559         if (bt == NULL)
1560                 return;
1561
1562         if (bt->ref == 1)
1563                 btree_sync(bt);
1564
1565         if (--bt->ref == 0) {
1566                 DPRINTF("ref is zero, closing btree %p:%s", bt, bt->path);
1567                 close(bt->fd);
1568                 mpage_flush(bt);
1569                 delete bt->hasher;
1570                 free(bt->page_cache);
1571                 free(bt->lru_queue);
1572                 free(bt->path);
1573                 free(bt);
1574         } else
1575                 DPRINTF("ref is now %d on btree %p", bt->ref, bt);
1576 }
1577
1578 void
1579 btree_close_nosync(struct btree *bt)
1580 {
1581         if (bt == NULL)
1582                 return;
1583
1584         if (--bt->ref == 0) {
1585                 DPRINTF("ref is zero, closing btree %p:%s", bt, bt->path);
1586                 close(bt->fd);
1587                 mpage_flush(bt);
1588                 delete bt->hasher;
1589                 free(bt->page_cache);
1590                 free(bt->lru_queue);
1591                 free(bt->path);
1592                 free(bt);
1593         } else
1594                 DPRINTF("ref is now %d on btree %p", bt->ref, bt);
1595 }
1596
1597 struct btree_txn *
1598 btree_get_txn(struct btree *bt)
1599 {
1600         assert(bt);
1601         return bt->txn;
1602 }
1603
1604 /* Search for key within a leaf page, using binary search.
1605  * Returns the smallest entry larger or equal to the key.
1606  * If exactp is non-null, stores whether the found entry was an exact match
1607  * in *exactp (1 or 0).
1608  * If kip is non-null, stores the index of the found entry in *kip.
1609  * If no entry larger of equal to the key is found, returns NULL.
1610  */
1611 static struct node *
1612 btree_search_node(struct btree *bt, struct mpage *mp, struct btval *key,
1613     int *exactp, unsigned int *kip)
1614 {
1615         unsigned int     i = 0;
1616         int              low, high;
1617         int              rc = 0;
1618         struct node     *node;
1619         struct btval     nodekey;
1620
1621         DPRINTF("searching for [%.*s] in %lu keys in %s page %u with prefix [%.*s]",
1622             key->size, (const char*)key->data,
1623             NUMKEYS(mp),
1624             IS_LEAF(mp) ? "leaf" : "branch",
1625             mp->pgno, (int)mp->prefix.len, (char *)mp->prefix.str);
1626
1627         assert(NUMKEYS(mp) > 0);
1628
1629         bzero(&nodekey, sizeof(nodekey));
1630
1631         low = IS_LEAF(mp) ? 0 : 1;
1632         high = NUMKEYS(mp) - 1;
1633         while (low <= high) {
1634                 i = (low + high) >> 1;
1635                 node = NODEPTR(mp, i);
1636
1637                 nodekey.size = node->ksize;
1638                 nodekey.data = NODEKEY(node);
1639
1640                 rc = bt_cmp(bt, key, &nodekey, &mp->prefix);
1641
1642                 if (IS_LEAF(mp))
1643                         DPRINTF("found leaf index %u [%.*s], rc = %i",
1644                             i, (int)nodekey.size, (char *)nodekey.data, rc);
1645                 else
1646                         DPRINTF("found branch index %u [%.*s -> %u], rc = %i",
1647                             i, (int)node->ksize, (char *)NODEKEY(node),
1648                             node->n_pgno, rc);
1649
1650                 if (rc == 0)
1651                         break;
1652                 if (rc > 0)
1653                         low = i + 1;
1654                 else
1655                         high = i - 1;
1656         }
1657
1658         if (rc > 0) {   /* Found entry is less than the key. */
1659                 i++;    /* Skip to get the smallest entry larger than key. */
1660                 if (i >= NUMKEYS(mp))
1661                         /* There is no entry larger or equal to the key. */
1662                         return NULL;
1663         }
1664         if (exactp)
1665                 *exactp = (rc == 0);
1666         if (kip)        /* Store the key index if requested. */
1667                 *kip = i;
1668
1669         return NODEPTR(mp, i);
1670 }
1671
1672 static void
1673 cursor_pop_page(struct cursor *cursor)
1674 {
1675         struct ppage    *top;
1676
1677         top = CURSOR_TOP(cursor);
1678         CURSOR_POP(cursor);
1679         top->mpage->ref--;
1680
1681         DPRINTF("popped page %u off cursor %p", top->mpage->pgno, cursor);
1682
1683         free(top);
1684 }
1685
1686 static struct ppage *
1687 cursor_push_page(struct cursor *cursor, struct mpage *mp)
1688 {
1689         struct ppage    *ppage;
1690
1691         DPRINTF("pushing page %u on cursor %p", mp->pgno, cursor);
1692
1693         if ((ppage = (struct ppage *)calloc(1, sizeof(struct ppage))) == NULL)
1694                 return NULL;
1695         ppage->mpage = mp;
1696         mp->ref++;
1697         CURSOR_PUSH(cursor, ppage);
1698         return ppage;
1699 }
1700
1701 static struct mpage *
1702 btree_get_mpage(struct btree *bt, pgno_t pgno)
1703 {
1704         struct mpage    *mp;
1705
1706         mp = mpage_lookup(bt, pgno);
1707         if (mp == NULL) {
1708                 if ((mp = (mpage *)calloc(1, sizeof(*mp))) == NULL)
1709                         return NULL;
1710                 if ((mp->page = (page *)malloc(bt->head.psize)) == NULL) {
1711                         free(mp);
1712                         return NULL;
1713                 }
1714                 if (btree_read_page(bt, pgno, mp->page) != BT_SUCCESS) {
1715                         mpage_free(mp);
1716                         return NULL;
1717                 }
1718                 mp->pgno = pgno;
1719                 mpage_add(bt, mp);
1720         } else
1721                 DPRINTF("returning page %u from cache", pgno);
1722
1723         DPRINTF("btree_get_mpage %p", mp);
1724         return mp;
1725 }
1726
1727 static void
1728 concat_prefix(struct btree *bt, char *s1, size_t n1, char *s2, size_t n2,
1729               char *cs, size_t *cn)
1730 {
1731         assert(*cn >= n1 + n2);
1732         if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
1733                 bcopy(s2, cs, n2);
1734                 bcopy(s1, cs + n2, n1);
1735         } else {
1736                 bcopy(s1, cs, n1);
1737                 bcopy(s2, cs + n1, n2);
1738         }
1739         *cn = n1 + n2;
1740 }
1741
1742 static void
1743 find_common_prefix(struct btree *bt, struct mpage *mp)
1744 {
1745         if (bt->cmp != NULL)
1746                 return;
1747
1748         indx_t                   lbound = 0, ubound = 0;
1749         struct mpage            *lp, *up;
1750         struct btkey             lprefix, uprefix;
1751
1752         mp->prefix.len = 0;
1753
1754         lp = mp;
1755         while (lp->parent != NULL) {
1756                 if (lp->parent_index > 0) {
1757                         lbound = lp->parent_index;
1758                         break;
1759                 }
1760                 lp = lp->parent;
1761         }
1762
1763         up = mp;
1764         while (up->parent != NULL) {
1765                 if (up->parent_index + 1 < (indx_t)NUMKEYS(up->parent)) {
1766                         ubound = up->parent_index + 1;
1767                         break;
1768                 }
1769                 up = up->parent;
1770         }
1771
1772         if (lp->parent != NULL && up->parent != NULL) {
1773                 expand_prefix(bt, lp->parent, lbound, &lprefix);
1774                 expand_prefix(bt, up->parent, ubound, &uprefix);
1775                 common_prefix(bt, &lprefix, &uprefix, &mp->prefix);
1776         }
1777         else if (mp->parent)
1778                 bcopy(&mp->parent->prefix, &mp->prefix, sizeof(mp->prefix));
1779
1780         DPRINTF("found common prefix [%.*s] (len %zu) for page %u",
1781             (int)mp->prefix.len, mp->prefix.str, mp->prefix.len, mp->pgno);
1782 }
1783
1784 static int
1785 btree_search_page_root(struct btree *bt, struct mpage *root, struct btval *key,
1786                        struct cursor *cursor, enum SearchType searchType, int modify, struct mpage **mpp)
1787 {
1788         struct mpage    *mp, *parent;
1789
1790         if (cursor && cursor_push_page(cursor, root) == NULL)
1791                 return BT_FAIL;
1792
1793         mp = root;
1794         DPRINTF("searchType=%d isBranch=%d", searchType, IS_BRANCH(mp));
1795         while (IS_BRANCH(mp)) {
1796                 unsigned int     i = 0;
1797                 struct node     *node;
1798
1799                 DPRINTF("branch page %u has %lu keys", mp->pgno, NUMKEYS(mp));
1800                 assert(NUMKEYS(mp) > 1);
1801                 DPRINTF("found index 0 to page %u", NODEPGNO(NODEPTR(mp, 0)));
1802
1803                 if (searchType == SearchFirst)  /* Initialize cursor to first page. */
1804                         i = 0;
1805                 else if (searchType == SearchLast) {    /* Initialize cursor to last page. */
1806                         i = NUMKEYS(mp) - 1;
1807                         DPRINTF("SearchLast i=%d", i);
1808                 } else {
1809                         int      exact;
1810                         node = btree_search_node(bt, mp, key, &exact, &i);
1811                         if (node == NULL)
1812                                 i = NUMKEYS(mp) - 1;
1813                         else if (!exact) {
1814                                 assert(i > 0);
1815                                 i--;
1816                         }
1817                 }
1818
1819                 if (key)
1820                         DPRINTF("following index %u for key %.*s",
1821                             i, (int)key->size, (char *)key->data);
1822                 assert(i < NUMKEYS(mp));
1823                 node = NODEPTR(mp, i);
1824
1825                 if (cursor)
1826                         CURSOR_TOP(cursor)->ki = i;
1827
1828                 parent = mp;
1829                 if ((mp = btree_get_mpage(bt, NODEPGNO(node))) == NULL)
1830                         return BT_FAIL;
1831                 mp->parent = parent;
1832                 mp->parent_index = i;
1833                 find_common_prefix(bt, mp);
1834
1835                 if (cursor && cursor_push_page(cursor, mp) == NULL)
1836                         return BT_FAIL;
1837
1838                 if (modify && (mp = mpage_touch(bt, mp)) == NULL)
1839                         return BT_FAIL;
1840         }
1841
1842         if (!IS_LEAF(mp)) {
1843                 DPRINTF("internal error, index points to a %02X page!?",
1844                     mp->page->flags);
1845                 return BT_FAIL;
1846         }
1847
1848         DPRINTF("found leaf page %u for key %.*s", mp->pgno,
1849             key ? (int)key->size : 0, key ? (char *)key->data : NULL);
1850
1851         *mpp = mp;
1852         return BT_SUCCESS;
1853 }
1854
1855 /* Search for the page a given key should be in.
1856  * Stores a pointer to the found page in *mpp.
1857  * Searches for key if searchType is SearchKey
1858  * Searches for the lowest page if searchType is SearchFirst
1859  * Searches for the highest page if searchType is SearchLast
1860  * If cursor is non-null, pushes parent pages on the cursor stack.
1861  * If modify is true, visited pages are updated with new page numbers.
1862  */
1863 static int
1864 btree_search_page(struct btree *bt, struct btree_txn *txn, struct btval *key,
1865                   struct cursor *cursor, enum SearchType searchType, int modify, struct mpage **mpp)
1866 {
1867         int              rc;
1868         pgno_t           root;
1869         struct mpage    *mp = 0;
1870
1871         /* Can't modify pages outside a transaction. */
1872         if (txn == NULL && modify) {
1873                 EPRINTF("cannot modify pages outside a transaction");
1874                 errno = EINVAL;
1875                 return BT_FAIL;
1876         }
1877
1878         /* Choose which root page to start with. If a transaction is given
1879          * use the root page from the transaction, otherwise read the last
1880          * committed root page.
1881          */
1882         if (txn == NULL) {
1883                 if ((rc = btree_read_meta(bt, NULL)) != BT_SUCCESS)
1884                         return rc;
1885                 root = bt->meta.root;
1886         } else if (F_ISSET(txn->flags, BT_TXN_ERROR)) {
1887                 EPRINTF("transaction has failed, must abort");
1888                 errno = EINVAL;
1889                 return BT_FAIL;
1890         } else
1891                 root = txn->root;
1892
1893         if (root == P_INVALID) {                /* Tree is empty. */
1894                 DPRINTF("tree is empty");
1895                 errno = ENOENT;
1896                 return BT_FAIL;
1897         }
1898
1899         if ((mp = btree_get_mpage(bt, root)) == NULL)
1900                 return BT_FAIL;
1901
1902         DPRINTF("root page has flags 0x%X mp=%p", mp->page->flags, mp);
1903
1904         assert(mp->parent == NULL);
1905         assert(mp->prefix.len == 0);
1906
1907         if (modify && !mp->dirty) {
1908                 if ((mp = mpage_touch(bt, mp)) == NULL)
1909                         return BT_FAIL;
1910                 txn->root = mp->pgno;
1911         }
1912
1913         return btree_search_page_root(bt, mp, key, cursor, searchType, modify, mpp);
1914 }
1915
1916 static int
1917 btree_read_data(struct btree *bt, struct mpage *mp, struct node *leaf,
1918     struct btval *data)
1919 {
1920         struct mpage    *omp;           /* overflow mpage */
1921         size_t           psz;
1922         size_t           max;
1923         size_t           sz = 0;
1924         pgno_t           pgno;
1925
1926         bzero(data, sizeof(*data));
1927         max = bt->head.psize - PAGEHDRSZ;
1928
1929         if (!F_ISSET(leaf->flags, F_BIGDATA)) {
1930                 data->size = leaf->n_dsize;
1931                 if (data->size > 0) {
1932                         if (mp == NULL) {
1933                                 if ((data->data = malloc(data->size)) == NULL)
1934                                         return BT_FAIL;
1935                                 bcopy(NODEDATA(leaf), data->data, data->size);
1936                                 data->free_data = 1;
1937                                 data->mp = NULL;
1938                         } else {
1939                                 data->data = NODEDATA(leaf);
1940                                 data->free_data = 0;
1941                                 data->mp = mp;
1942                                 mp->ref++;
1943                         }
1944                 }
1945                 return BT_SUCCESS;
1946         }
1947
1948         /* Read overflow data.
1949          */
1950         DPRINTF("allocating %u byte for overflow data", leaf->n_dsize);
1951         if ((data->data = malloc(leaf->n_dsize)) == NULL)
1952                 return BT_FAIL;
1953         data->size = leaf->n_dsize;
1954         data->free_data = 1;
1955         data->mp = NULL;
1956         bcopy(NODEDATA(leaf), &pgno, sizeof(pgno));
1957         for (sz = 0; sz < data->size; ) {
1958                 if ((omp = btree_get_mpage(bt, pgno)) == NULL ||
1959                     !F_ISSET(omp->page->flags, P_OVERFLOW)) {
1960                         DPRINTF("read overflow page %u failed", pgno);
1961                         free(data->data);
1962                         mpage_free(omp);
1963                         return BT_FAIL;
1964                 }
1965                 psz = data->size - sz;
1966                 if (psz > max)
1967                         psz = max;
1968                 bcopy(omp->page->ptrs, (char *)data->data + sz, psz);
1969                 sz += psz;
1970                 pgno = omp->page->p_next_pgno;
1971         }
1972
1973         return BT_SUCCESS;
1974 }
1975
1976 int
1977 btree_txn_get(struct btree *bt, struct btree_txn *txn,
1978     struct btval *key, struct btval *data)
1979 {
1980         int              rc, exact;
1981         struct node     *leaf;
1982         struct mpage    *mp;
1983
1984         assert(key);
1985         assert(data);
1986         DPRINTF("===> get key [%.*s]", (int)key->size, (char *)key->data);
1987
1988         if (bt != NULL && txn != NULL && bt != txn->bt) {
1989                 errno = EINVAL;
1990                 return BT_FAIL;
1991         }
1992
1993         if (bt == NULL) {
1994                 if (txn == NULL) {
1995                         errno = EINVAL;
1996                         return BT_FAIL;
1997                 }
1998                 bt = txn->bt;
1999         }
2000
2001         if (key->size == 0 || key->size > MAXKEYSIZE) {
2002                 errno = EINVAL;
2003                 return BT_FAIL;
2004         }
2005
2006         if ((rc = btree_search_page(bt, txn, key, NULL, SearchKey, 0, &mp)) != BT_SUCCESS)
2007                 return rc;
2008
2009         leaf = btree_search_node(bt, mp, key, &exact, NULL);
2010         if (leaf && exact)
2011                 rc = btree_read_data(bt, mp, leaf, data);
2012         else {
2013                 errno = ENOENT;
2014                 rc = BT_FAIL;
2015         }
2016
2017         mpage_prune(bt);
2018         return rc;
2019 }
2020
2021 static int
2022 btree_sibling(struct cursor *cursor, int move_right, int rightmost)
2023 {
2024         int              rc;
2025         struct node     *indx;
2026         struct ppage    *parent, *top;
2027         struct mpage    *mp;
2028
2029         top = CURSOR_TOP(cursor);
2030         if ((parent = SLIST_NEXT(top, entry)) == NULL) {
2031                 errno = ENOENT;
2032                 return BT_FAIL;                 /* root has no siblings */
2033         }
2034
2035         DPRINTF("parent page is page %u, index %u",
2036             parent->mpage->pgno, parent->ki);
2037
2038         cursor_pop_page(cursor);
2039         if (move_right ? (parent->ki + 1 >= NUMKEYS(parent->mpage))
2040                        : (parent->ki == 0)) {
2041                 DPRINTF("no more keys left, moving to %s node of %s sibling",
2042                         rightmost ? "rightmost" : "leftmost",
2043                         move_right ? "right" : "left");
2044                 if ((rc = btree_sibling(cursor, move_right, rightmost)) != BT_SUCCESS)
2045                         return rc;
2046                 parent = CURSOR_TOP(cursor);
2047         } else {
2048                 if (move_right)
2049                         parent->ki++;
2050                 else
2051                         parent->ki--;
2052                 DPRINTF("just moving to %s index key %u",
2053                     move_right ? "right" : "left", parent->ki);
2054         }
2055         assert(IS_BRANCH(parent->mpage));
2056
2057         indx = NODEPTR(parent->mpage, parent->ki);
2058         if ((mp = btree_get_mpage(cursor->bt, indx->n_pgno)) == NULL)
2059                 return BT_FAIL;
2060         mp->parent = parent->mpage;
2061         mp->parent_index = parent->ki;
2062
2063         top = cursor_push_page(cursor, mp);
2064         find_common_prefix(cursor->bt, mp);
2065         if (rightmost)
2066             top->ki = NUMKEYS(mp)-1;
2067
2068         return BT_SUCCESS;
2069 }
2070
2071 static int
2072 bt_set_key(struct btree *bt, struct mpage *mp, struct node *node,
2073     struct btval *key)
2074 {
2075         if (key == NULL)
2076                 return 0;
2077
2078         if (mp->prefix.len > 0) {
2079                 key->size = node->ksize + mp->prefix.len;
2080                 key->data = malloc(key->size);
2081                 if (key->data == NULL)
2082                         return -1;
2083                 concat_prefix(bt,
2084                               mp->prefix.str, mp->prefix.len,
2085                               NODEKEY(node), node->ksize,
2086                               (char *)key->data, &key->size);
2087                 key->free_data = 1;
2088         } else {
2089                 key->size = node->ksize;
2090                 key->data = NODEKEY(node);
2091                 key->free_data = 0;
2092                 key->mp = mp;
2093                 mp->ref++;
2094         }
2095
2096         return 0;
2097 }
2098
2099 static int
2100 btree_cursor_next(struct cursor *cursor, struct btval *key, struct btval *data)
2101 {
2102         struct ppage    *top;
2103         struct mpage    *mp;
2104         struct node     *leaf;
2105
2106         if (cursor->eof) {
2107                 errno = ENOENT;
2108                 return BT_FAIL;
2109         }
2110
2111         assert(cursor->initialized);
2112
2113         top = CURSOR_TOP(cursor);
2114         mp = top->mpage;
2115
2116         DPRINTF("cursor_next: top page is %u in cursor %p", mp->pgno, cursor);
2117
2118         if (top->ki + 1 >= NUMKEYS(mp)) {
2119                 DPRINTF("=====> move to next sibling page");
2120                 if (btree_sibling(cursor, 1, 0) != BT_SUCCESS) {
2121                         cursor->eof = 1;
2122                         return BT_FAIL;
2123                 }
2124                 top = CURSOR_TOP(cursor);
2125                 mp = top->mpage;
2126                 DPRINTF("next page is %u, key index %u", mp->pgno, top->ki);
2127         } else
2128                 top->ki++;
2129
2130         DPRINTF("==> cursor points to page %u with %lu keys, key index %u",
2131             mp->pgno, NUMKEYS(mp), top->ki);
2132
2133         assert(IS_LEAF(mp));
2134         leaf = NODEPTR(mp, top->ki);
2135
2136         if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
2137                 return BT_FAIL;
2138
2139         if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
2140                 return BT_FAIL;
2141
2142         return BT_SUCCESS;
2143 }
2144
2145 static int
2146 btree_cursor_prev(struct cursor *cursor, struct btval *key, struct btval *data)
2147 {
2148         struct ppage    *top;
2149         struct mpage    *mp;
2150         struct node     *leaf;
2151
2152         if (cursor->eof) {
2153                 errno = ENOENT;
2154                 return BT_FAIL;
2155         }
2156
2157         assert(cursor->initialized);
2158
2159         top = CURSOR_TOP(cursor);
2160         mp = top->mpage;
2161
2162         DPRINTF("top page is %u in cursor %p", mp->pgno, cursor);
2163
2164         if (top->ki - 1 == -1u) {
2165                 DPRINTF("=====> move to prev sibling page");
2166                 if (btree_sibling(cursor, 0, 1) != BT_SUCCESS) {
2167                         cursor->eof = 1;
2168                         return BT_FAIL;
2169                 }
2170                 top = CURSOR_TOP(cursor);
2171                 mp = top->mpage;
2172                 DPRINTF("next page is %u, key index %u", mp->pgno, top->ki);
2173         } else
2174                 top->ki--;
2175
2176         DPRINTF("==> cursor points to page %u with %lu keys, key index %u",
2177                 mp->pgno, NUMKEYS(mp), top->ki);
2178
2179         assert(IS_LEAF(mp));
2180         leaf = NODEPTR(mp, top->ki);
2181
2182         if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
2183                 return BT_FAIL;
2184
2185         if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
2186                 return BT_FAIL;
2187
2188         return BT_SUCCESS;
2189 }
2190
2191 static int
2192 btree_cursor_set(struct cursor *cursor, struct btval *key, struct btval *data,
2193     int *exactp)
2194 {
2195         int              rc;
2196         struct node     *leaf;
2197         struct mpage    *mp;
2198         struct ppage    *top;
2199
2200         assert(cursor);
2201         assert(key);
2202         assert(key->size > 0);
2203
2204         rc = btree_search_page(cursor->bt, cursor->txn, key, cursor, SearchKey, 0, &mp);
2205         if (rc != BT_SUCCESS)
2206                 return rc;
2207         assert(IS_LEAF(mp));
2208
2209         top = CURSOR_TOP(cursor);
2210         leaf = btree_search_node(cursor->bt, mp, key, exactp, &top->ki);
2211         if (exactp != NULL && !*exactp) {
2212                 /* BT_CURSOR_EXACT specified and not an exact match. */
2213                 errno = ENOENT;
2214                 return BT_FAIL;
2215         }
2216
2217         if (leaf == NULL) {
2218                 DPRINTF("===> inexact leaf not found, goto sibling");
2219                 if (btree_sibling(cursor, 1, 0) != BT_SUCCESS)
2220                         return BT_FAIL;         /* no entries matched */
2221                 top = CURSOR_TOP(cursor);
2222                 top->ki = 0;
2223                 mp = top->mpage;
2224                 assert(IS_LEAF(mp));
2225                 leaf = NODEPTR(mp, 0);
2226         }
2227
2228         cursor->initialized = 1;
2229         cursor->eof = 0;
2230
2231         if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
2232                 return BT_FAIL;
2233
2234         if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
2235                 return BT_FAIL;
2236         DPRINTF("==> cursor placed on key %.*s",
2237             (int)key->size, (char *)key->data);
2238
2239         return BT_SUCCESS;
2240 }
2241
2242 static int
2243 btree_cursor_first(struct cursor *cursor, struct btval *key, struct btval *data)
2244 {
2245         int              rc;
2246         struct mpage    *mp;
2247         struct node     *leaf;
2248
2249         rc = btree_search_page(cursor->bt, cursor->txn, NULL, cursor, SearchFirst, 0, &mp);
2250         if (rc != BT_SUCCESS)
2251                 return rc;
2252         assert(IS_LEAF(mp));
2253
2254         leaf = NODEPTR(mp, 0);
2255         cursor->initialized = 1;
2256         cursor->eof = 0;
2257
2258         if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
2259                 return BT_FAIL;
2260
2261         if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
2262                 return BT_FAIL;
2263
2264         return BT_SUCCESS;
2265 }
2266
2267 static int
2268 btree_cursor_last(struct cursor *cursor, struct btval *key, struct btval *data)
2269 {
2270         int              rc;
2271         struct mpage    *mp;
2272         struct node     *leaf;
2273         struct ppage    *top;
2274
2275         rc = btree_search_page(cursor->bt, cursor->txn, NULL, cursor, SearchLast, 0, &mp);
2276         if (rc != BT_SUCCESS)
2277                 return rc;
2278         assert(IS_LEAF(mp));
2279
2280         top = CURSOR_TOP(cursor);
2281         // get the last leaf in the page
2282         top->ki = NUMKEYS(mp)-1;
2283         leaf = NODEPTR(mp, top->ki);
2284         cursor->initialized = 1;
2285         cursor->eof = 0;
2286
2287         if (data && btree_read_data(cursor->bt, mp, leaf, data) != BT_SUCCESS)
2288                 return BT_FAIL;
2289
2290         if (bt_set_key(cursor->bt, mp, leaf, key) != 0)
2291                 return BT_FAIL;
2292
2293         return BT_SUCCESS;
2294 }
2295
2296 int
2297 btree_cursor_get(struct cursor *cursor, struct btval *key, struct btval *data,
2298     enum cursor_op op)
2299 {
2300         int              rc;
2301         int              exact = 0;
2302
2303         assert(cursor);
2304
2305         switch (op) {
2306         case BT_CURSOR:
2307         case BT_CURSOR_EXACT:
2308                 while (CURSOR_TOP(cursor) != NULL)
2309                         cursor_pop_page(cursor);
2310                 if (key == NULL || key->size == 0 || key->size > MAXKEYSIZE) {
2311                         errno = EINVAL;
2312                         rc = BT_FAIL;
2313                 } else if (op == BT_CURSOR_EXACT)
2314                         rc = btree_cursor_set(cursor, key, data, &exact);
2315                 else
2316                         rc = btree_cursor_set(cursor, key, data, NULL);
2317                 break;
2318         case BT_NEXT:
2319                 if (!cursor->initialized)
2320                         rc = btree_cursor_first(cursor, key, data);
2321                 else
2322                         rc = btree_cursor_next(cursor, key, data);
2323                 break;
2324         case BT_PREV:
2325                 if (!cursor->initialized)
2326                         rc = btree_cursor_last(cursor, key, data);
2327                 else
2328                         rc = btree_cursor_prev(cursor, key, data);
2329                 break;
2330         case BT_FIRST:
2331                 while (CURSOR_TOP(cursor) != NULL)
2332                         cursor_pop_page(cursor);
2333                 rc = btree_cursor_first(cursor, key, data);
2334                 break;
2335         case BT_LAST:
2336                 while (CURSOR_TOP(cursor) != NULL)
2337                         cursor_pop_page(cursor);
2338                 rc = btree_cursor_last(cursor, key, data);
2339                 break;
2340         default:
2341                 DPRINTF("unhandled/unimplemented cursor operation %u", op);
2342                 rc = BT_FAIL;
2343                 break;
2344         }
2345
2346         mpage_prune(cursor->bt);
2347
2348         return rc;
2349 }
2350
2351 struct btree *
2352 btree_cursor_bt(struct cursor *cursor)
2353 {
2354         assert(cursor);
2355         return cursor->bt;
2356 }
2357
2358 struct btree_txn *
2359 btree_cursor_txn(struct cursor *cursor)
2360 {
2361         assert(cursor);
2362         return cursor->txn;
2363 }
2364
2365 static struct mpage *
2366 btree_new_page(struct btree *bt, uint32_t flags)
2367 {
2368         struct mpage    *mp;
2369
2370         assert(bt != NULL);
2371         assert(bt->txn != NULL);
2372
2373         DPRINTF("allocating new mpage %u, page size %u, flags %0X",
2374             bt->txn->next_pgno, bt->head.psize, flags);
2375         if ((mp = (mpage *)calloc(1, sizeof(*mp))) == NULL)
2376                 return NULL;
2377         if ((mp->page = (page *)malloc(bt->head.psize)) == NULL) {
2378                 free(mp);
2379                 return NULL;
2380         }
2381         memset(mp->page, 0, bt->head.psize);
2382         mp->pgno = mp->page->pgno = bt->txn->next_pgno++;
2383         mp->page->flags = flags;
2384         mp->page->lower = PAGEHDRSZ;
2385         mp->page->upper = bt->head.psize;
2386
2387         if (IS_BRANCH(mp))
2388                 bt->meta.branch_pages++;
2389         else if (IS_LEAF(mp))
2390                 bt->meta.leaf_pages++;
2391         else if (IS_OVERFLOW(mp))
2392                 bt->meta.overflow_pages++;
2393
2394         mpage_add(bt, mp);
2395         mpage_dirty(bt, mp);
2396
2397         return mp;
2398 }
2399
2400 static size_t
2401 bt_leaf_size(struct btree *bt, struct mpage *mp, struct btval *key, struct btval *data)
2402 {
2403         size_t           sz;
2404
2405         sz = LEAFSIZE(key, data);
2406         if (bt_is_overflow(bt, mp, key->size, data->size)) {
2407                 /* put on overflow page */
2408                 sz -= data->size - sizeof(pgno_t);
2409         }
2410
2411         return sz + sizeof(indx_t);
2412 }
2413
2414 static int
2415 bt_is_overflow(struct btree *bt, struct mpage *mp, size_t ksize, size_t dsize)
2416 {
2417         assert(bt && mp);
2418 #ifdef ENABLE_BIG_KEYS
2419         size_t node_size = dsize + ksize + NODESIZE;
2420         if ((node_size + sizeof(indx_t) > SIZELEFT(mp))
2421             || (NUMKEYS(mp) == 0 && (SIZELEFT(mp) - (node_size + sizeof(indx_t))) < MAXKEYSIZE))
2422                 return 1;
2423 #else
2424         (void)ksize;
2425         if (dsize >= bt->head.psize / BT_MINKEYS)
2426                 return 1;
2427
2428 #endif
2429         return 0;
2430 }
2431
2432 static size_t
2433 bt_branch_size(struct btree *bt, struct btval *key)
2434 {
2435         size_t           sz;
2436
2437         sz = INDXSIZE(key);
2438         if (sz >= bt->head.psize / BT_MINKEYS) {
2439                 /* put on overflow page */
2440                 /* not implemented */
2441                 /* sz -= key->size - sizeof(pgno_t); */
2442         }
2443
2444         return sz + sizeof(indx_t);
2445 }
2446
2447 static int
2448 btree_write_overflow_data(struct btree *bt, struct page *p, struct btval *data)
2449 {
2450         size_t           done = 0;
2451         size_t           sz;
2452         size_t           max;
2453         pgno_t          *linkp;                 /* linked page stored here */
2454         struct mpage    *next = NULL;
2455
2456         max = bt->head.psize - PAGEHDRSZ;
2457
2458         while (done < data->size) {
2459                 if (next != NULL)
2460                         p = next->page;
2461                 linkp = &p->p_next_pgno;
2462                 if (data->size - done > max) {
2463                         /* need another overflow page */
2464                         if ((next = btree_new_page(bt, P_OVERFLOW)) == NULL)
2465                                 return BT_FAIL;
2466                         *linkp = next->pgno;
2467                         DPRINTF("linking overflow page %u", next->pgno);
2468                 } else
2469                         *linkp = 0;             /* indicates end of list */
2470                 sz = data->size - done;
2471                 if (sz > max)
2472                         sz = max;
2473                 DPRINTF("copying %zu bytes to overflow page %u", sz, p->pgno);
2474                 bcopy((char *)data->data + done, p->ptrs, sz);
2475                 done += sz;
2476         }
2477
2478         return BT_SUCCESS;
2479 }
2480
2481 /* Key prefix should already be stripped.
2482  */
2483 static int
2484 btree_add_node(struct btree *bt, struct mpage *mp, indx_t indx,
2485     struct btval *key, struct btval *data, pgno_t pgno, uint8_t flags)
2486 {
2487         unsigned int     i;
2488         size_t           node_size = NODESIZE;
2489         indx_t           ofs;
2490         struct node     *node;
2491         struct page     *p;
2492         struct mpage    *ofp = NULL;            /* overflow page */
2493
2494         p = mp->page;
2495         assert(p->upper >= p->lower);
2496
2497         DPRINTF("add node [%.*s] to %s page %u at index %i, key size %zu",
2498             key ? (int)key->size : 0, key ? (char *)key->data : NULL,
2499             IS_LEAF(mp) ? "leaf" : "branch",
2500             mp->pgno, indx, key ? key->size : 0);
2501
2502         if (key != NULL)
2503                 node_size += key->size;
2504
2505         if (IS_LEAF(mp)) {
2506                 assert(data);
2507                 node_size += data->size;
2508                 if (F_ISSET(flags, F_BIGDATA)) {
2509                         /* Data already on overflow page. */
2510                         node_size -= data->size - sizeof(pgno_t);
2511 #ifdef ENABLE_BIG_KEYS
2512                 } else if (bt_is_overflow(bt, mp, (key ? key->size : 0), data->size)) {
2513 #else
2514                 } else if (bt_is_overflow(bt, mp, (key ? key->size : 0), data->size)
2515                            || (node_size + sizeof(indx_t) > SIZELEFT(mp))) {
2516 #endif
2517                         /* Put data on overflow page. */
2518                         DPRINTF("data size is %zu, put on overflow page",
2519                             data->size);
2520                         node_size -= data->size - sizeof(pgno_t);
2521                         if ((ofp = btree_new_page(bt, P_OVERFLOW)) == NULL)
2522                                 return BT_FAIL;
2523                         DPRINTF("allocated overflow page %u", ofp->pgno);
2524                         flags |= F_BIGDATA;
2525                 }
2526         }
2527
2528         if (node_size + sizeof(indx_t) > SIZELEFT(mp)) {
2529                 DPRINTF("not enough room in page %u, got %lu ptrs",
2530                     mp->pgno, NUMKEYS(mp));
2531                 DPRINTF("upper - lower = %u - %u = %u", p->upper, p->lower,
2532                     p->upper - p->lower);
2533                 DPRINTF("node size = %zu", node_size);
2534                 return BT_FAIL;
2535         }
2536
2537         /* Move higher pointers up one slot. */
2538         for (i = NUMKEYS(mp); i > indx; i--)
2539                 p->ptrs[i] = p->ptrs[i - 1];
2540
2541         /* Adjust free space offsets. */
2542         ofs = p->upper - node_size;
2543         assert(ofs >= p->lower + sizeof(indx_t));
2544         p->ptrs[indx] = ofs;
2545         p->upper = ofs;
2546         p->lower += sizeof(indx_t);
2547
2548         /* Write the node data. */
2549         node = NODEPTR(mp, indx);
2550         node->ksize = (key == NULL) ? 0 : key->size;
2551         node->flags = flags;
2552         if (IS_LEAF(mp)) {
2553                 node->n_dsize = data->size;
2554         } else {
2555                 node->n_pgno = pgno;
2556         }
2557
2558         if (key)
2559                 bcopy(key->data, NODEKEY(node), key->size);
2560
2561         if (IS_LEAF(mp)) {
2562                 assert(key);
2563                 if (ofp == NULL) {
2564                         if (F_ISSET(flags, F_BIGDATA))
2565                                 bcopy(data->data, node->data + key->size,
2566                                     sizeof(pgno_t));
2567                         else
2568                                 bcopy(data->data, node->data + key->size,
2569                                     data->size);
2570                 } else {
2571                         bcopy(&ofp->pgno, node->data + key->size,
2572                             sizeof(pgno_t));
2573                         if (btree_write_overflow_data(bt, ofp->page,
2574                             data) == BT_FAIL)
2575                                 return BT_FAIL;
2576                 }
2577         }
2578
2579         return BT_SUCCESS;
2580 }
2581
2582 static void
2583 btree_del_node(struct btree *, struct mpage *mp, indx_t indx)
2584 {
2585         unsigned int     sz;
2586         indx_t           i, j, numkeys, ptr;
2587         struct node     *node;
2588         char            *base;
2589
2590         DPRINTF("delete node %u on %s page %u", indx,
2591             IS_LEAF(mp) ? "leaf" : "branch", mp->pgno);
2592         assert(indx < NUMKEYS(mp));
2593
2594         node = NODEPTR(mp, indx);
2595         sz = NODESIZE + node->ksize;
2596         if (IS_LEAF(mp)) {
2597                 if (F_ISSET(node->flags, F_BIGDATA))
2598                         sz += sizeof(pgno_t);
2599                 else
2600                         sz += NODEDSZ(node);
2601         }
2602
2603         ptr = mp->page->ptrs[indx];
2604         numkeys = NUMKEYS(mp);
2605         for (i = j = 0; i < numkeys; i++) {
2606                 if (i != indx) {
2607                         mp->page->ptrs[j] = mp->page->ptrs[i];
2608                         if (mp->page->ptrs[i] < ptr)
2609                                 mp->page->ptrs[j] += sz;
2610                         j++;
2611                 }
2612         }
2613
2614         base = (char *)mp->page + mp->page->upper;
2615         bcopy(base, base + sz, ptr - mp->page->upper);
2616
2617         mp->page->lower -= sizeof(indx_t);
2618         mp->page->upper += sz;
2619 }
2620
2621 struct cursor *
2622 btree_txn_cursor_open(struct btree *bt, struct btree_txn *txn)
2623 {
2624         struct cursor   *cursor;
2625
2626         if (bt != NULL && txn != NULL && bt != txn->bt) {
2627                 errno = EINVAL;
2628                 DPRINTF("bt=%p does not belong to txn=%p (txn->bt=%p)", bt, txn, txn->bt);
2629                 return NULL;
2630         }
2631
2632         if (bt == NULL) {
2633                 if (txn == NULL) {
2634                         errno = EINVAL;
2635                         DPRINTF("bt and txn both null");
2636                         return NULL;
2637                 }
2638                 bt = txn->bt;
2639         }
2640
2641         if ((cursor = (struct cursor *)calloc(1, sizeof(struct cursor))) != NULL) {
2642                 SLIST_INIT(&cursor->stack);
2643                 cursor->bt = bt;
2644                 cursor->txn = txn;
2645                 btree_ref(bt);
2646         }
2647
2648         return cursor;
2649 }
2650
2651 void
2652 btree_cursor_close(struct cursor *cursor)
2653 {
2654         if (cursor != NULL) {
2655                 while (!CURSOR_EMPTY(cursor))
2656                         cursor_pop_page(cursor);
2657
2658                 btree_close(cursor->bt);
2659                 free(cursor);
2660         }
2661 }
2662
2663 static int
2664 btree_update_key(struct btree *, struct mpage *mp, indx_t indx,
2665                  struct btval *key)
2666 {
2667         indx_t                   ptr, i, numkeys;
2668         int                      delta;
2669         size_t                   len;
2670         struct node             *node;
2671         char                    *base;
2672
2673         node = NODEPTR(mp, indx);
2674         ptr = mp->page->ptrs[indx];
2675         DPRINTF("update key %u (ofs %u) [%.*s] to [%.*s] on page %u",
2676             indx, ptr,
2677             (int)node->ksize, (char *)NODEKEY(node),
2678             (int)key->size, (char *)key->data,
2679             mp->pgno);
2680
2681         if (key->size != node->ksize) {
2682                 delta = key->size - node->ksize;
2683                 if (delta > 0 && SIZELEFT(mp) < delta) {
2684                         DPRINTF("OUCH! Not enough room, delta = %d", delta);
2685                         return BT_FAIL;
2686                 }
2687
2688                 numkeys = NUMKEYS(mp);
2689                 for (i = 0; i < numkeys; i++) {
2690                         if (mp->page->ptrs[i] <= ptr)
2691                                 mp->page->ptrs[i] -= delta;
2692                 }
2693
2694                 base = (char *)mp->page + mp->page->upper;
2695                 len = ptr - mp->page->upper + NODESIZE;
2696                 bcopy(base, base - delta, len);
2697                 mp->page->upper -= delta;
2698
2699                 node = NODEPTR(mp, indx);
2700                 node->ksize = key->size;
2701         }
2702
2703         bcopy(key->data, NODEKEY(node), key->size);
2704
2705         return BT_SUCCESS;
2706 }
2707
2708 static int
2709 btree_adjust_prefix(struct btree *bt, struct mpage *src, int delta)
2710 {
2711         indx_t           i;
2712         struct node     *node;
2713         struct btkey     tmpkey;
2714         struct btval     key;
2715
2716         DPRINTF("adjusting prefix lengths on page %u with delta %d",
2717             src->pgno, delta);
2718         assert(delta != 0);
2719
2720         for (i = 0; i < NUMKEYS(src); i++) {
2721                 node = NODEPTR(src, i);
2722                 tmpkey.len = node->ksize - delta;
2723                 if (delta > 0) {
2724                         if (F_ISSET(bt->flags, BT_REVERSEKEY))
2725                                 bcopy(NODEKEY(node), tmpkey.str, tmpkey.len);
2726                         else
2727                                 bcopy((char *)NODEKEY(node) + delta, tmpkey.str,
2728                                     tmpkey.len);
2729                 } else {
2730                         if (F_ISSET(bt->flags, BT_REVERSEKEY)) {
2731                                 bcopy(NODEKEY(node), tmpkey.str, node->ksize);
2732                                 bcopy(src->prefix.str, tmpkey.str + node->ksize,
2733                                     -delta);
2734                         } else {
2735                                 bcopy(src->prefix.str + src->prefix.len + delta,
2736                                     tmpkey.str, -delta);
2737                                 bcopy(NODEKEY(node), tmpkey.str - delta,
2738                                     node->ksize);
2739                         }
2740                 }