diff options
author | Martin Hedenfal <martinh@cvs.openbsd.org> | 2010-06-11 05:29:23 +0000 |
---|---|---|
committer | Martin Hedenfal <martinh@cvs.openbsd.org> | 2010-06-11 05:29:23 +0000 |
commit | 9cf55a6cafa20b4836f2d6665f22b4dbec7bdfb6 (patch) | |
tree | db2eec9b24d837ad575ec3587b37fb52ad8d40ea /usr.sbin/ldapd | |
parent | 0d2f6ae37a8233a3b060cd47cf10fa080e4ff212 (diff) |
Append a "tombstone" meta page after a database has been compacted. This
allows other processes to pick up the change and re-open the file.
Diffstat (limited to 'usr.sbin/ldapd')
-rw-r--r-- | usr.sbin/ldapd/btree.c | 86 | ||||
-rw-r--r-- | usr.sbin/ldapd/btree.h | 3 |
2 files changed, 58 insertions, 31 deletions
diff --git a/usr.sbin/ldapd/btree.c b/usr.sbin/ldapd/btree.c index 2c7f166a217..f1ae013b6a3 100644 --- a/usr.sbin/ldapd/btree.c +++ b/usr.sbin/ldapd/btree.c @@ -1,4 +1,4 @@ -/* $OpenBSD: btree.c,v 1.5 2010/06/10 19:36:39 martinh Exp $ */ +/* $OpenBSD: btree.c,v 1.6 2010/06/11 05:29:22 martinh Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -93,6 +93,7 @@ struct page { /* represents an on-disk page */ struct bt_meta { /* meta (footer) page content */ uint32_t magic; /* really needed? */ uint32_t version; +#define BT_TOMBSTONE 0x01 /* file is replaced */ uint32_t flags; uint32_t psize; /* page size */ pgno_t root; /* page number of root page */ @@ -132,6 +133,7 @@ static int mpage_cmp(struct mpage *a, struct mpage *b); static struct mpage *mpage_lookup(struct btree *bt, pgno_t pgno); static void mpage_add(struct btree *bt, struct mpage *mp); static void mpage_del(struct btree *bt, struct mpage *mp); +static void mpage_flush(struct btree *bt); static struct mpage *mpage_copy(struct mpage *mp); static void mpage_prune(struct btree *bt); static void mpage_dirty(struct btree *bt, struct mpage *mp); @@ -197,7 +199,7 @@ struct btree { struct page_cache *page_cache; struct lru_queue *lru_queue; struct btree_txn *txn; /* current write transaction */ - int ref; /* increased by cursors */ + int ref; /* increased by cursors & txn */ struct btree_stat stat; off_t size; /* current file size */ }; @@ -232,7 +234,8 @@ static int btree_search_page(struct btree *bt, static void btree_init_meta(struct btree *bt); static int btree_is_meta_page(struct page *p); static int btree_read_meta(struct btree *bt, pgno_t *p_next); -static int btree_write_meta(struct btree *bt, pgno_t root); +static int btree_write_meta(struct btree *bt, pgno_t root, + unsigned int flags); static struct node *btree_search_node(struct btree *bt, struct mpage *mp, struct btval *key, int *exactp, unsigned int *kip); @@ -482,6 +485,17 @@ mpage_del(struct btree *bt, struct mpage *mp) TAILQ_REMOVE(bt->lru_queue, mp, lru_next); } +static void +mpage_flush(struct btree *bt) +{ + struct mpage *mp; + + while ((mp = RB_MIN(page_cache, bt->page_cache)) != NULL) { + mpage_del(bt, mp); + free(mp); + } +} + static struct mpage * mpage_copy(struct mpage *mp) { @@ -630,7 +644,8 @@ btree_txn_begin(struct btree *bt, int rdonly) txn->bt = bt; bt->ref++; - if ((rc = btree_read_meta(bt, &txn->next_pgno)) == BT_FAIL) { + if ((rc = btree_read_meta(bt, &txn->next_pgno)) == BT_FAIL || + rc == BT_DEAD) { btree_txn_abort(txn); return NULL; } @@ -768,7 +783,7 @@ btree_txn_commit(struct btree_txn *txn) } while (!done); if (btree_sync(bt) != 0 || - btree_write_meta(bt, txn->root) != BT_SUCCESS || + btree_write_meta(bt, txn->root, 0) != BT_SUCCESS || btree_sync(bt) != 0) { btree_txn_abort(txn); return BT_FAIL; @@ -782,7 +797,7 @@ done: } static int -btree_write_meta(struct btree *bt, pgno_t root) +btree_write_meta(struct btree *bt, pgno_t root, unsigned int flags) { ssize_t rc; @@ -797,6 +812,7 @@ btree_write_meta(struct btree *bt, pgno_t root) bt->metapage->pgno = bt->txn->next_pgno++; bt->meta->root = root; + bt->meta->flags = flags; bt->meta->created_at = time(0); bt->meta->revisions++; SHA1((unsigned char *)bt->meta, METAHASHLEN, bt->meta->hash); @@ -916,7 +932,13 @@ btree_read_meta(struct btree *bt, pgno_t *p_next) break; /* no meta page found */ if (rc == BT_SUCCESS && btree_is_meta_page(bt->metapage)) { bt->meta = METADATA(bt->metapage); - return BT_SUCCESS; + DPRINTF("flags = 0x%x", bt->meta->flags); + if (F_ISSET(bt->meta->flags, BT_TOMBSTONE)) { + DPRINTF("file is dead"); + errno = EAGAIN; + return BT_DEAD; + } else + return BT_SUCCESS; } --meta_pgno; /* scan backwards to first valid meta page */ } @@ -931,7 +953,7 @@ fail: struct btree * btree_open_fd(int fd, uint32_t flags) { - int fl; + int fl, rc; struct btree *bt; fl = fcntl(fd, F_GETFL, 0); @@ -956,7 +978,7 @@ btree_open_fd(int fd, uint32_t flags) if ((bt->metapage = calloc(1, PAGESIZE)) == NULL) goto fail; - if (btree_read_meta(bt, NULL) == BT_FAIL) + if ((rc = btree_read_meta(bt, NULL)) == BT_FAIL || rc == BT_DEAD) goto fail; if (bt->meta == NULL) { @@ -1019,20 +1041,17 @@ btree_open(const char *path, uint32_t flags, mode_t mode) void btree_close(struct btree *bt) { - struct mpage *mp; + if (bt == NULL) + return; - if (bt != NULL && --bt->ref == 0) { + if (--bt->ref == 0) { DPRINTF("ref is zero, closing btree %p", bt); close(bt->fd); - - /* Free page_cache. */ - while ((mp = RB_MIN(page_cache, bt->page_cache)) != NULL) { - mpage_del(bt, mp); - free(mp); - } + mpage_flush(bt); free(bt->page_cache); free(bt); - } + } else + DPRINTF("ref is now %d", bt->ref); } /* Search for key within a leaf page, using binary search. @@ -2800,17 +2819,17 @@ btree_compact(struct btree *bt) int rc, fd, old_fd; char *compact_path = NULL; struct btree_txn *txn; - pgno_t root; + pgno_t root, next_pgno; assert(bt != NULL); if (bt->path == NULL) return BT_FAIL; - if ((rc = btree_read_meta(bt, NULL)) == BT_FAIL) - return BT_FAIL; - else if (rc == BT_NOTFOUND) + if ((rc = btree_read_meta(bt, NULL)) == BT_NOTFOUND) return BT_SUCCESS; + else if (rc != BT_SUCCESS) + return rc; asprintf(&compact_path, "%s.compact.XXXXXX", bt->path); fd = mkstemp(compact_path); @@ -2824,13 +2843,14 @@ btree_compact(struct btree *bt) if ((txn = btree_txn_begin(bt, 0)) == NULL) goto failed; + next_pgno = bt->txn->next_pgno; bt->txn->next_pgno = 0; root = btree_compact_tree(bt, bt->meta->root, fd); if (root == P_INVALID) goto failed; bt->fd = fd; bt->meta->revisions = 0; - if (btree_write_meta(bt, root) != BT_SUCCESS) + if (btree_write_meta(bt, root, 0) != BT_SUCCESS) goto failed; fsync(fd); @@ -2839,11 +2859,18 @@ btree_compact(struct btree *bt) if (rename(compact_path, bt->path) != 0) goto failed; - /* XXX: write a "reopen me" meta page for other processes to see */ - btree_txn_abort(txn); - close(old_fd); + /* Write a "tombstone" meta page so other processes can pick up + * the change and re-open the file. + */ + bt->fd = old_fd; + bt->txn->next_pgno = next_pgno; + if (btree_write_meta(bt, P_INVALID, BT_TOMBSTONE) != BT_SUCCESS) + goto failed; + bt->fd = fd; + btree_txn_abort(txn); free(compact_path); + mpage_flush(bt); return BT_SUCCESS; failed: @@ -2859,11 +2886,10 @@ failed: int btree_revert(struct btree *bt) { - if (btree_read_meta(bt, NULL) == BT_FAIL) - return BT_FAIL; + int rc; - if (bt->meta == NULL) - return BT_SUCCESS; + if ((rc = btree_read_meta(bt, NULL)) != BT_SUCCESS) + return rc; DPRINTF("truncating file at page %u", bt->meta->root); return ftruncate(bt->fd, PAGESIZE * bt->meta->root); diff --git a/usr.sbin/ldapd/btree.h b/usr.sbin/ldapd/btree.h index 926cea6b0f4..f8dee1576c0 100644 --- a/usr.sbin/ldapd/btree.h +++ b/usr.sbin/ldapd/btree.h @@ -1,4 +1,4 @@ -/* $OpenBSD: btree.h,v 1.1 2010/05/31 17:36:31 martinh Exp $ */ +/* $OpenBSD: btree.h,v 1.2 2010/06/11 05:29:22 martinh Exp $ */ /* * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se> @@ -56,6 +56,7 @@ enum cursor_op { /* cursor operations */ #define BT_SUCCESS 0 #define BT_NOTFOUND 1 #define BT_EXISTS 2 +#define BT_DEAD 3 /* file has been replaced */ /* btree flags */ #define BT_NOSYNC 0x01 /* don't fsync after commit */ |