+BtLatchSet *bt_pinleaf (BtMgr *mgr, uid page_no, ushort thread_no)
+{
+uint hashidx = page_no % mgr->leafhash;
+BtLatchSet *latch;
+uint entry, idx;
+BtPage page;
+
+ // try to find our entry
+
+ bt_mutexlock(mgr->leaftable[hashidx].latch);
+
+ if( entry = mgr->leaftable[hashidx].entry ) do
+ {
+ latch = mgr->leafsets + entry;
+ if( page_no == latch->page_no )
+ break;
+ } while( entry = latch->next );
+
+ // found our entry: increment pin
+
+ if( entry ) {
+ latch = mgr->leafsets + entry;
+ bt_mutexlock(latch->modify);
+ latch->pin |= CLOCK_bit;
+ latch->pin++;
+if( !latch->leaf )
+abort();
+ bt_releasemutex(latch->modify);
+ bt_releasemutex(mgr->leaftable[hashidx].latch);
+ return latch;
+ }
+
+ // find and reuse unpinned entry
+
+trynext:
+
+ entry = bt_availleaf (mgr);
+ latch = mgr->leafsets + entry;
+if( latch->page_no )
+if( !latch->leaf )
+abort();
+
+ idx = latch->page_no % mgr->leafhash;
+
+ // if latch is on a different hash chain
+ // unlink from the old page_no chain
+
+ if( latch->page_no )
+ if( idx != hashidx ) {
+
+ // skip over this entry if latch not available
+
+ if( !bt_mutextry (mgr->leaftable[idx].latch) ) {
+ bt_releasemutex(latch->modify);
+ goto trynext;
+ }
+
+ if( latch->prev )
+ mgr->leafsets[latch->prev].next = latch->next;
+ else
+ mgr->leaftable[idx].entry = latch->next;
+
+ if( latch->next )
+ mgr->leafsets[latch->next].prev = latch->prev;
+
+ bt_releasemutex (mgr->leaftable[idx].latch);
+ }
+
+ page = (BtPage)(((uid)entry << mgr->page_bits << mgr->leaf_xtra) + mgr->leafpool);
+
+ // update permanent page area in btree from buffer pool
+ // no read-lock is required since page is not pinned.
+
+if( latch->page_no )
+if( !latch->leaf )
+abort();
+ if( latch->dirty )
+ if( mgr->err = bt_writepage (mgr, page, latch->page_no, 1) )
+ return mgr->line = __LINE__, mgr->err_thread = thread_no, NULL;
+ else
+ latch->dirty = 0;
+
+ if( bt_readpage (mgr, page, page_no, 1) )
+ return mgr->line = __LINE__, NULL;
+
+ // link page as head of hash table chain
+ // if this is a never before used entry,
+ // or it was previously on a different
+ // hash table chain. Otherwise, just
+ // leave it in its current hash table
+ // chain position.
+
+ if( !latch->page_no || hashidx != idx ) {
+ if( latch->next = mgr->leaftable[hashidx].entry )
+ mgr->leafsets[latch->next].prev = entry;
+
+ mgr->leaftable[hashidx].entry = entry;
+ latch->prev = 0;
+ }
+
+ // fill in latch structure
+
+ latch->pin = CLOCK_bit | 1;
+ latch->page_no = page_no;
+ latch->leaf = 1;
+
+ bt_releasemutex (latch->modify);
+ bt_releasemutex (mgr->leaftable[hashidx].latch);
+ return latch;
+}
+
+// pin page in non-leaf buffer pool
+// return with latchset pinned
+
+BtLatchSet *bt_pinlatch (BtMgr *mgr, uid page_no, ushort thread_no)