static PyObject* validate_dict_key( Member* keymember, PyObject* owner, PyObject* dict ) { PyObject* key; PyObject* value; Py_ssize_t pos = 0; PyDictPtr newptr( PyDict_New() ); if( !newptr ) return 0; while( PyDict_Next( dict, &pos, &key, &value ) ) { PyObjectPtr keyptr( member_validate( keymember, owner, _py_null, key ) ); if( !keyptr ) return 0; PyObjectPtr valptr( newref( value ) ); if( !newptr.set_item( keyptr, valptr ) ) return 0; } return newptr.release(); }
uint32_t btree1FindSlot (Btree1Page *page, uint8_t *key, uint32_t keyLen, bool stopper) { uint32_t diff, higher = page->cnt, low = 1, slot; uint32_t good = 0; assert(higher > 0); // are we being asked for the stopper(fence) key? if (stopper) return higher; // make stopper key an infinite fence value if( page->right.bits ) higher++; else good++; // low is the lowest candidate. // loop ends when they meet // higher is already // tested as .ge. the passed key. while( (diff = higher - low) ) { slot = low + diff / 2; if( btree1KeyCmp (keyptr(page, slot), key, keyLen) < 0 ) low = slot + 1; else higher = slot, good++; } // return zero if key is on next right page return good ? higher : 0; }
DbStatus btree1LoadPage(DbMap *map, Btree1Set *set, void *key, uint32_t keyLen, uint8_t lvl, Btree1Lock lock, bool stopper) { Btree1Index *btree1 = btree1index(map); uint8_t drill = 0xff, *ptr; Btree1Page *prevPage = NULL; Btree1Lock mode, prevMode; DbAddr prevPageNo; set->pageNo.bits = btree1->root.bits; prevPageNo.bits = 0; // start at our idea of the root level of the btree1 and drill down do { // determine lock mode of drill level mode = (drill == lvl) ? lock : Btree1_lockRead; set->page = getObj(map, set->pageNo); // release parent or left sibling page if( prevPageNo.bits ) { btree1UnlockPage(prevPage, prevMode); prevPageNo.bits = 0; } // obtain mode lock btree1LockPage(set->page, mode); if( set->page->free ) return DB_BTREE_error; // re-read and re-lock root after determining actual level of root if( set->page->lvl != drill) { assert(drill == 0xff); drill = set->page->lvl; if( lock != Btree1_lockRead && drill == lvl ) { btree1UnlockPage(set->page, mode); continue; } } assert(lvl <= set->page->lvl); prevPageNo.bits = set->pageNo.bits; prevPage = set->page; prevMode = mode; // find key on page at this level // and descend to requested level if( !set->page->kill ) if( (set->slotIdx = btree1FindSlot (set->page, key, keyLen, stopper)) ) { if( drill == lvl ) return DB_OK; // find next non-dead slot -- the fence key if nothing else while( slotptr(set->page, set->slotIdx)->dead ) if( set->slotIdx++ < set->page->cnt ) continue; else return DB_BTREE_error; // get next page down ptr = keyptr(set->page, set->slotIdx); set->pageNo.bits = btree1GetPageNo(ptr + keypre(ptr), keylen(ptr)); assert(drill > 0); drill--; continue; } // or slide right into next page set->pageNo.bits = set->page->right.bits; } while( set->pageNo.bits ); // return error on end of right chain return DB_BTREE_error; }
uint8_t *btree1Key(Btree1Page *page, uint32_t idx) { return keyptr(page, idx); }
BtMgr *bt_mgr (char *name, uint mode, uint bits, uint poolmax, uint segsize, uint hashsize) { uint lvl, attr, cacheblk, last; BtPage alloc; int lockmode; off64_t size; uint amt[1]; BtMgr* mgr; BtKey key; #ifndef unix SYSTEM_INFO sysinfo[1]; #endif // determine sanity of page size and buffer pool if( bits > BT_maxbits ) bits = BT_maxbits; else if( bits < BT_minbits ) bits = BT_minbits; if( !poolmax ) return NULL; // must have buffer pool #ifdef unix mgr = calloc (1, sizeof(BtMgr)); switch (mode & 0x7fff) { case BT_rw: mgr->idx = open ((char*)name, O_RDWR | O_CREAT, 0666); lockmode = 1; break; case BT_ro: default: mgr->idx = open ((char*)name, O_RDONLY); lockmode = 0; break; } if( mgr->idx == -1 ) return free(mgr), NULL; cacheblk = 4096; // minimum mmap segment size for unix #else mgr = GlobalAlloc (GMEM_FIXED|GMEM_ZEROINIT, sizeof(BtMgr)); attr = FILE_ATTRIBUTE_NORMAL; switch (mode & 0x7fff) { case BT_rw: mgr->idx = CreateFile(name, GENERIC_READ| GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, attr, NULL); lockmode = 1; break; case BT_ro: default: mgr->idx = CreateFile(name, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, attr, NULL); lockmode = 0; break; } if( mgr->idx == INVALID_HANDLE_VALUE ) return GlobalFree(mgr), NULL; // normalize cacheblk to multiple of sysinfo->dwAllocationGranularity GetSystemInfo(sysinfo); cacheblk = sysinfo->dwAllocationGranularity; #endif #ifdef unix alloc = malloc (BT_maxpage); *amt = 0; // read minimum page size to get root info if( size = lseek (mgr->idx, 0L, 2) ) { if( pread(mgr->idx, alloc, BT_minpage, 0) == BT_minpage ) bits = alloc->bits; else return free(mgr), free(alloc), NULL; } else if( mode == BT_ro ) return bt_mgrclose (mgr), NULL; #else alloc = VirtualAlloc(NULL, BT_maxpage, MEM_COMMIT, PAGE_READWRITE); size = GetFileSize(mgr->idx, amt); if( size || *amt ) { if( !ReadFile(mgr->idx, (char *)alloc, BT_minpage, amt, NULL) ) return bt_mgrclose (mgr), NULL; bits = alloc->bits; } else if( mode == BT_ro ) return bt_mgrclose (mgr), NULL; #endif mgr->page_size = 1 << bits; mgr->page_bits = bits; mgr->poolmax = poolmax; mgr->mode = mode; if( cacheblk < mgr->page_size ) cacheblk = mgr->page_size; // mask for partial memmaps mgr->poolmask = (cacheblk >> bits) - 1; // see if requested size of pages per memmap is greater if( (1 << segsize) > mgr->poolmask ) mgr->poolmask = (1 << segsize) - 1; mgr->seg_bits = 0; while( (1 << mgr->seg_bits) <= mgr->poolmask ) mgr->seg_bits++; mgr->hashsize = hashsize; #ifdef unix mgr->pool = calloc (poolmax, sizeof(BtPool)); mgr->hash = calloc (hashsize, sizeof(ushort)); mgr->latch = calloc (hashsize, sizeof(BtLatch)); mgr->pooladvise = calloc (poolmax, (mgr->poolmask + 8) / 8); #else mgr->pool = GlobalAlloc (GMEM_FIXED|GMEM_ZEROINIT, poolmax * sizeof(BtPool)); mgr->hash = GlobalAlloc (GMEM_FIXED|GMEM_ZEROINIT, hashsize * sizeof(ushort)); mgr->latch = GlobalAlloc (GMEM_FIXED|GMEM_ZEROINIT, hashsize * sizeof(BtLatch)); #endif if( size || *amt ) goto mgrxit; // initializes an empty b-tree with root page and page of leaves memset (alloc, 0, 1 << bits); bt_putid(alloc->right, MIN_lvl+1); alloc->bits = mgr->page_bits; #ifdef unix if( write (mgr->idx, alloc, mgr->page_size) < mgr->page_size ) return bt_mgrclose (mgr), NULL; #else if( !WriteFile (mgr->idx, (char *)alloc, mgr->page_size, amt, NULL) ) return bt_mgrclose (mgr), NULL; if( *amt < mgr->page_size ) return bt_mgrclose (mgr), NULL; #endif memset (alloc, 0, 1 << bits); alloc->bits = mgr->page_bits; for( lvl=MIN_lvl; lvl--; ) { slotptr(alloc, 1)->off = mgr->page_size - 3; bt_putid(slotptr(alloc, 1)->id, lvl ? MIN_lvl - lvl + 1 : 0); // next(lower) page number key = keyptr(alloc, 1); key->len = 2; // create stopper key key->key[0] = 0xff; key->key[1] = 0xff; alloc->min = mgr->page_size - 3; alloc->lvl = lvl; alloc->cnt = 1; alloc->act = 1; #ifdef unix if( write (mgr->idx, alloc, mgr->page_size) < mgr->page_size ) return bt_mgrclose (mgr), NULL; #else if( !WriteFile (mgr->idx, (char *)alloc, mgr->page_size, amt, NULL) ) return bt_mgrclose (mgr), NULL; if( *amt < mgr->page_size ) return bt_mgrclose (mgr), NULL; #endif } // create empty page area by writing last page of first // segment area (other pages are zeroed by O/S) if( mgr->poolmask ) { memset(alloc, 0, mgr->page_size); last = mgr->poolmask; while( last < MIN_lvl + 1 ) last += mgr->poolmask + 1; #ifdef unix pwrite(mgr->idx, alloc, mgr->page_size, last << mgr->page_bits); #else SetFilePointer (mgr->idx, last << mgr->page_bits, NULL, FILE_BEGIN); if( !WriteFile (mgr->idx, (char *)alloc, mgr->page_size, amt, NULL) ) return bt_mgrclose (mgr), NULL; if( *amt < mgr->page_size ) return bt_mgrclose (mgr), NULL; #endif } mgrxit: #ifdef unix free (alloc); #else VirtualFree (alloc, 0, MEM_RELEASE); #endif return mgr; }