]> pd.if.org Git - btree/blobdiff - btree2u.c
Remove debug code.
[btree] / btree2u.c
index bd97dd2a609a397e5bae9106b27baccd06033944..308c9f28ba82ea37791fa93b209b67841bff4758 100644 (file)
--- a/btree2u.c
+++ b/btree2u.c
@@ -43,6 +43,7 @@ REDISTRIBUTION OF THIS SOFTWARE.
 #include <stdlib.h>
 #include <time.h>
 #include <fcntl.h>
+#include <io.h>
 #endif
 
 #include <memory.h>
@@ -65,6 +66,17 @@ typedef unsigned int         uint;
 #define BT_minpage             (1 << BT_minbits)       // minimum page size
 #define BT_maxpage             (1 << BT_maxbits)       // maximum page size
 
+//  BTree page number constants
+#define ALLOC_page             0
+#define ROOT_page              1
+#define LEAF_page              2
+#define LATCH_page             3
+
+//     Number of levels to create in a new BTree
+
+#define MIN_lvl                        2
+#define MAX_lvl                        15
+
 /*
 There are five lock types for each node in three independent sets: 
 1. (set 1) AccessIntent: Sharable. Going to Read the node. Incompatible with NodeDelete. 
@@ -148,11 +160,13 @@ typedef struct BtPage_ {
 typedef struct {
        struct BtPage_ alloc[2];        // next & free page_nos in right ptr
        BtSpinLatch lock[1];            // allocation area lite latch
-       uint latchdeployed;                     // highest number of latch entries deployed
-       uint nlatchpage;                        // number of latch pages at BT_latch
-       uint latchtotal;                        // number of page latch entries
-       uint latchhash;                         // number of latch hash table slots
-       uint latchvictim;                       // next latch hash entry to examine
+       volatile uint latchdeployed;// highest number of latch entries deployed
+       volatile uint nlatchpage;       // number of latch pages at BT_latch
+       volatile uint latchtotal;       // number of page latch entries
+       volatile uint latchhash;        // number of latch hash table slots
+       volatile uint latchvictim;      // next latch hash entry to examine
+       volatile uint safelevel;        // safe page level in cache
+       volatile uint cache[MAX_lvl];// cache census counts by btree level
 } BtLatchMgr;
 
 //  latch hash table entries
@@ -169,11 +183,17 @@ typedef struct {
        BtSpinLatch readwr[1];          // read/write page lock
        BtSpinLatch access[1];          // Access Intent/Page delete
        BtSpinLatch parent[1];          // Posting of fence key in parent
+       volatile ushort pin;            // number of pins/level/clock bits
        volatile uint next;                     // next entry in hash table chain
        volatile uint prev;                     // prev entry in hash table chain
-       volatile uint pin;                      // number of outstanding pins
 } BtLatchSet;
 
+#define CLOCK_mask 0xe000
+#define CLOCK_unit 0x2000
+#define PIN_mask 0x07ff
+#define LVL_mask 0x1800
+#define LVL_shift 11
+
 //     The object structure for Btree access
 
 typedef struct _BtDb {
@@ -235,16 +255,6 @@ extern uid bt_uid (BtDb *bt, uint slot);
 extern uint bt_tod (BtDb *bt, uint slot);
 #endif
 
-//  BTree page number constants
-#define ALLOC_page             0
-#define ROOT_page              1
-#define LEAF_page              2
-#define LATCH_page             3
-
-//     Number of levels to create in a new BTree
-
-#define MIN_lvl                        2
-
 //  The page is allocated from low and hi ends.
 //  The key offsets and row-id's are allocated
 //  from the bottom, while the text of the key
@@ -533,6 +543,7 @@ BTERR bt_latchlink (BtDb *bt, uint hashidx, uint slot, uid page_no)
 {
 BtPage page = (BtPage)((uid)slot * bt->page_size + bt->pagepool);
 BtLatchSet *latch = bt->latchsets + slot;
+int lvl;
 
        if( latch->next = bt->table[hashidx].slot )
                bt->latchsets[latch->next].prev = slot;
@@ -542,7 +553,21 @@ BtLatchSet *latch = bt->latchsets + slot;
        latch->prev = 0;
        latch->pin = 1;
 
-       return bt_readpage (bt, page, page_no);
+       if( bt_readpage (bt, page, page_no) )
+               return bt->err;
+
+       lvl = page->lvl << LVL_shift;
+       if( lvl > LVL_mask )
+               lvl = LVL_mask;
+       latch->pin |= lvl;              // store lvl
+       latch->pin |= lvl << 3; // initialize clock
+
+#ifdef unix
+       __sync_fetch_and_add (&bt->latchmgr->cache[page->lvl], 1);
+#else
+       _InterlockedAdd(&bt->latchmgr->cache[page->lvl], 1);
+#endif
+       return bt->err = 0;
 }
 
 //     release latch pin
@@ -552,7 +577,7 @@ void bt_unpinlatch (BtLatchSet *latch)
 #ifdef unix
        __sync_fetch_and_add(&latch->pin, -1);
 #else
-       _InterlockedDecrement (&latch->pin);
+       _InterlockedDecrement16 (&latch->pin);
 #endif
 }
 
@@ -564,11 +589,12 @@ BtLatchSet *bt_pinlatch (BtDb *bt, uid page_no)
 uint hashidx = page_no % bt->latchmgr->latchhash;
 BtLatchSet *latch;
 uint slot, idx;
+uint lvl, cnt;
 off64_t off;
 uint amt[1];
 BtPage page;
 
-  //  try to find unpinned entry
+  //  try to find our entry
 
   bt_spinwritelock(bt->table[hashidx].latch);
 
@@ -579,33 +605,21 @@ BtPage page;
                break;
   } while( slot = latch->next );
 
-  //  found our entry, bring to front of hash chain
+  //  found our entry
+  //  increment clock
 
   if( slot ) {
        latch = bt->latchsets + slot;
+       lvl = (latch->pin & LVL_mask) >> LVL_shift;
+       lvl *= CLOCK_unit * 2;
+       lvl |= CLOCK_unit;
 #ifdef unix
        __sync_fetch_and_add(&latch->pin, 1);
+       __sync_fetch_and_or(&latch->pin, lvl);
 #else
-       _InterlockedIncrement (&latch->pin);
+       _InterlockedIncrement16 (&latch->pin);
+       _InterlockedOr16 (&latch->pin, lvl);
 #endif
-       //  unlink our entry from its hash chain position
-
-       if( latch->prev )
-               bt->latchsets[latch->prev].next = latch->next;
-       else
-               bt->table[hashidx].slot = latch->next;
-
-       if( latch->next )
-               bt->latchsets[latch->next].prev = latch->prev;
-
-       //  now link into head of the hash chain
-
-       if( latch->next = bt->table[hashidx].slot )
-               bt->latchsets[latch->next].prev = slot;
-
-       bt->table[hashidx].slot = slot;
-       latch->prev = 0;
-
        bt_spinreleasewrite(bt->table[hashidx].latch);
        return latch;
   }
@@ -630,40 +644,67 @@ BtPage page;
 #else
        _InterlockedDecrement (&bt->latchmgr->latchdeployed);
 #endif
-  //  find and reuse previous lru lock entry on victim hash chain
+  //  find and reuse previous entry on victim
 
   while( 1 ) {
 #ifdef unix
-       idx = __sync_fetch_and_add(&bt->latchmgr->latchvictim, 1);
+       slot = __sync_fetch_and_add(&bt->latchmgr->latchvictim, 1);
 #else
-       idx = _InterlockedIncrement (&bt->latchmgr->latchvictim) - 1;
+       slot = _InterlockedIncrement (&bt->latchmgr->latchvictim) - 1;
 #endif
        // try to get write lock on hash chain
        //      skip entry if not obtained
-       //      or has outstanding locks
+       //      or has outstanding pins
 
-       idx %= bt->latchmgr->latchhash;
+       slot %= bt->latchmgr->latchtotal;
 
-       if( !bt_spinwritetry (bt->table[idx].latch) )
-               continue;
+       //      on slot wraparound, check census
+       //      count and increment safe level
 
-       if( slot = bt->table[idx].slot )
-         while( 1 ) {
-               latch = bt->latchsets + slot;
-               if( !latch->next )
-                       break;
-               slot = latch->next;
-         }
+       cnt = bt->latchmgr->cache[bt->latchmgr->safelevel];
 
-       if( !slot || latch->pin ) {
-               bt_spinreleasewrite (bt->table[idx].latch);
+       if( !slot ) {
+         if( cnt < bt->latchmgr->latchtotal / 10 )
+#ifdef unix
+               __sync_fetch_and_add(&bt->latchmgr->safelevel, 1);
+#else
+               _InterlockedIncrement (&bt->latchmgr->safelevel);
+#endif
+         continue;
+       }
+
+       latch = bt->latchsets + slot;
+       idx = latch->page_no % bt->latchmgr->latchhash;
+       lvl = (latch->pin & LVL_mask) >> LVL_shift;
+
+       //      see if we are evicting this level yet
+
+       if( lvl > bt->latchmgr->safelevel )
+               continue;
+
+       if( !bt_spinwritetry (bt->table[idx].latch) )
                continue;
+
+       if( latch->pin & ~LVL_mask ) {
+         if( latch->pin & CLOCK_mask )
+#ifdef unix
+               __sync_fetch_and_add(&latch->pin, -CLOCK_unit);
+#else
+               _InterlockedExchangeAdd16 (&latch->pin, -CLOCK_unit);
+#endif
+         bt_spinreleasewrite (bt->table[idx].latch);
+         continue;
        }
 
        //  update permanent page area in btree
 
        page = (BtPage)((uid)slot * bt->page_size + bt->pagepool);
-
+#ifdef unix
+       posix_fadvise (bt->idx, page_no << bt->page_bits, bt->page_size, POSIX_FADV_WILLNEED);
+       __sync_fetch_and_add (&bt->latchmgr->cache[page->lvl], -1);
+#else
+       _InterlockedAdd(&bt->latchmgr->cache[page->lvl], -1);
+#endif
        if( page->dirty )
          if( bt_writepage (bt, page, latch->page_no) )
                return NULL;
@@ -750,7 +791,8 @@ struct flock lock[1];
        bt = calloc (1, sizeof(BtDb));
 
        bt->idx = open ((char*)name, O_RDWR | O_CREAT, 0666);
-
+       posix_fadvise( bt->idx, 0, 0, POSIX_FADV_RANDOM);
        if( bt->idx == -1 ) {
                fprintf(stderr, "unable to open %s\n", name);
                return free(bt), NULL;
@@ -789,7 +831,7 @@ struct flock lock[1];
 #endif 
 
 #ifdef unix
-       latchmgr = malloc (BT_maxpage);
+       latchmgr = valloc (BT_maxpage);
        *amt = 0;
 
        // read minimum page size to get root info
@@ -880,13 +922,12 @@ struct flock lock[1];
        // clear out buffer pool pages
 
        memset(latchmgr, 0, bt->page_size);
-       last = MIN_lvl;
+       last = MIN_lvl + nlatchpage;
 
-       while( ++last < ((MIN_lvl + 1 + nlatchpage) ) )
-         if( bt_writepage (bt, latchmgr->alloc, last) ) {
+       if( bt_writepage (bt, latchmgr->alloc, last) ) {
                fprintf (stderr, "Unable to write buffer pool page %.8x\n", last);
                return bt_close (bt), NULL;
-         }
+       }
                
 #ifdef unix
        free (latchmgr);
@@ -919,6 +960,7 @@ btlatch:
                fprintf (stderr, "Unable to mmap buffer pool, errno = %d", errno);
                return bt_close (bt), NULL;
        }
+       madvise (bt->table, (uid)nlatchpage << bt->page_bits, MADV_RANDOM | MADV_WILLNEED);
 #else
        flag = PAGE_READWRITE;
        bt->halloc = CreateFileMapping(bt->idx, NULL, flag, 0, ((uid)nlatchpage + LATCH_page) * bt->page_size, NULL);
@@ -940,7 +982,7 @@ btlatch:
        bt->latchsets = (BtLatchSet *)(bt->pagepool - (uid)bt->latchmgr->latchtotal * sizeof(BtLatchSet));
 
 #ifdef unix
-       bt->mem = malloc (2 * bt->page_size);
+       bt->mem = valloc (2 * bt->page_size);
 #else
        bt->mem = VirtualAlloc(NULL, 2 * bt->page_size, MEM_COMMIT, PAGE_READWRITE);
 #endif
@@ -1883,15 +1925,21 @@ uint bt_audit (BtDb *bt)
 uint idx, hashidx;
 uid next, page_no;
 BtLatchSet *latch;
+uint blks[64];
 uint cnt = 0;
 BtPage page;
 uint amt[1];
 BtKey ptr;
 
+#ifdef unix
+       posix_fadvise( bt->idx, 0, 0, POSIX_FADV_SEQUENTIAL);
+#endif
        if( *(ushort *)(bt->latchmgr->lock) )
                fprintf(stderr, "Alloc page locked\n");
        *(ushort *)(bt->latchmgr->lock) = 0;
 
+       memset (blks, 0, sizeof(blks));
+
        for( idx = 1; idx <= bt->latchmgr->latchdeployed; idx++ ) {
                latch = bt->latchsets + idx;
                if( *(ushort *)latch->readwr )
@@ -1906,30 +1954,30 @@ BtKey ptr;
                        fprintf(stderr, "latchset %d parentlocked for page %.8x\n", idx, latch->page_no);
                *(ushort *)latch->parent = 0;
 
-               if( latch->pin ) {
+               if( latch->pin & PIN_mask ) {
                        fprintf(stderr, "latchset %d pinned for page %.8x\n", idx, latch->page_no);
                        latch->pin = 0;
                }
                page = (BtPage)((uid)idx * bt->page_size + bt->pagepool);
+               blks[page->lvl]++;
 
            if( page->dirty )
                 if( bt_writepage (bt, page, latch->page_no) )
                        fprintf(stderr, "Page %.8x Write Error\n", latch->page_no);
        }
 
+       for( idx = 0; blks[idx]; idx++ )
+               fprintf(stderr, "cache: %d lvl %d blocks\n", blks[idx], idx);
+
        for( hashidx = 0; hashidx < bt->latchmgr->latchhash; hashidx++ ) {
          if( *(ushort *)(bt->table[hashidx].latch) )
                        fprintf(stderr, "hash entry %d locked\n", hashidx);
 
          *(ushort *)(bt->table[hashidx].latch) = 0;
-
-         if( idx = bt->table[hashidx].slot ) do {
-               latch = bt->latchsets + idx;
-               if( latch->pin )
-                       fprintf(stderr, "latchset %d pinned for page %.8x\n", idx, latch->page_no);
-         } while( idx = latch->next );
        }
 
+       memset (blks, 0, sizeof(blks));
+
        next = bt->latchmgr->nlatchpage + LATCH_page;
        page_no = LEAF_page;
 
@@ -1944,12 +1992,17 @@ BtKey ptr;
                 }
                 if( !bt->frame->lvl )
                        cnt += bt->frame->act;
+                blks[bt->frame->lvl]++;
                }
 
                if( page_no > LEAF_page )
                        next = page_no + 1;
                page_no = next;
        }
+
+       for( idx = 0; blks[idx]; idx++ )
+               fprintf(stderr, "btree: %d lvl %d blocks\n", blks[idx], idx);
+
        return cnt - 1;
 }
 
@@ -2024,15 +2077,20 @@ int ch, cnt = 0, bits = 12, idx;
 unsigned char key[256];
 double done, start;
 uid next, page_no;
+BtLatchSet *latch;
 float elapsed;
 time_t tod[1];
 uint scan = 0;
 uint len = 0;
 uint map = 0;
+BtPage page;
 BtKey ptr;
 BtDb *bt;
 FILE *in;
 
+#ifdef WIN32
+       _setmode (1, _O_BINARY);
+#endif
        if( argc < 4 ) {
                fprintf (stderr, "Usage: %s idx_file src_file Read/Write/Scan/Delete/Find/Count [page_bits mapped_pool_pages start_line_number]\n", argv[0]);
                fprintf (stderr, "  page_bits: size of btree page in bits\n");
@@ -2061,15 +2119,27 @@ FILE *in;
 
        switch(argv[3][0]| 0x20)
        {
-       case 'a':
-               fprintf(stderr, "started audit for %s\n", argv[2]);
+       case 'p':       // display page
+               if( latch = bt_pinlatch (bt, off) )
+                       page = bt_mappage (bt, latch);
+               else
+                       fprintf(stderr, "unable to read page %.8x\n", off);
+
+               write (1, page, bt->page_size);
+               break;
+
+       case 'a':       // buffer pool audit
+               fprintf(stderr, "started audit for %s\n", argv[1]);
                cnt = bt_audit (bt);
-               fprintf(stderr, "finished audit for %s, %d keys\n", argv[2], cnt);
+               fprintf(stderr, "finished audit for %s, %d keys\n", argv[1], cnt);
                break;
 
-       case 'w':
+       case 'w':       // write keys
                fprintf(stderr, "started indexing for %s\n", argv[2]);
-               if( argc > 2 && (in = fopen (argv[2], "rb")) )
+               if( argc > 2 && (in = fopen (argv[2], "rb")) ) {
+#ifdef unix
+                 posix_fadvise( fileno(in), 0, 0, POSIX_FADV_NOREUSE);
+#endif
                  while( ch = getc(in), ch != EOF )
                        if( ch == '\n' )
                        {
@@ -2082,12 +2152,16 @@ FILE *in;
                        }
                        else if( len < 245 )
                                key[len++] = ch;
+                 }
                fprintf(stderr, "finished adding keys for %s, %d \n", argv[2], line);
                break;
 
-       case 'd':
+       case 'd':       // delete keys
                fprintf(stderr, "started deleting keys for %s\n", argv[2]);
-               if( argc > 2 && (in = fopen (argv[2], "rb")) )
+               if( argc > 2 && (in = fopen (argv[2], "rb")) ) {
+#ifdef unix
+                 posix_fadvise( fileno(in), 0, 0, POSIX_FADV_NOREUSE);
+#endif
                  while( ch = getc(in), ch != EOF )
                        if( ch == '\n' )
                        {
@@ -2100,12 +2174,16 @@ FILE *in;
                        }
                        else if( len < 245 )
                                key[len++] = ch;
+                 }
                fprintf(stderr, "finished deleting keys for %s, %d \n", argv[2], line);
                break;
 
-       case 'f':
+       case 'f':       // find keys
                fprintf(stderr, "started finding keys for %s\n", argv[2]);
-               if( argc > 2 && (in = fopen (argv[2], "rb")) )
+               if( argc > 2 && (in = fopen (argv[2], "rb")) ) {
+#ifdef unix
+                 posix_fadvise( fileno(in), 0, 0, POSIX_FADV_NOREUSE);
+#endif
                  while( ch = getc(in), ch != EOF )
                        if( ch == '\n' )
                        {
@@ -2120,10 +2198,11 @@ FILE *in;
                        }
                        else if( len < 245 )
                                key[len++] = ch;
+                 }
                fprintf(stderr, "finished search of %d keys for %s, found %d\n", line, argv[2], found);
                break;
 
-       case 's':
+       case 's':       // scan and print keys
                fprintf(stderr, "started scaning\n");
                cnt = len = key[0] = 0;
 
@@ -2142,7 +2221,7 @@ FILE *in;
                fprintf(stderr, " Total keys read %d\n", cnt - 1);
                break;
 
-       case 'c':
+       case 'c':       // count keys
          fprintf(stderr, "started counting\n");
          cnt = 0;
 
@@ -2150,8 +2229,6 @@ FILE *in;
          page_no = LEAF_page;
 
          while( page_no < bt_getid(bt->latchmgr->alloc->right) ) {
-         BtLatchSet *latch;
-         BtPage page;
                if( latch = bt_pinlatch (bt, page_no) )
                        page = bt_mappage (bt, latch);
                if( !page->free && !page->lvl )