}
if ( db->npage ) {
- db->Cache=(TBTMemPage**)t0malloc( sizeof(TBTMemPage*)*db->npage );
+ db->Cache=(TBTMemPage**)t0malloc( sizeof(TBTMemPage*)*HASHSIZE(db->npage) );
db->curpage=0;
}
if ( db->npage ) {
u_int32_t i;
-
- for(i=0; i<db->curpage; i++)
- tfree( db->Cache[i] );
+ TBTMemPage *ptr,*tmp;
+
+ for(i=0; i<HASHSIZE(db->npage); i++) {
+ ptr = db->Cache[i];
+ while(ptr) {
+ tmp = ptr->link;
+ tfree(ptr);
+ ptr=tmp;
+ }
+ }
tfree( db->Cache );
}
return (rc) ? TBT_ERROR : TBT_OK;
}
+static int
+cmpNPage(const void *a, const void *b) {
+ tassert( (*(TBTMemPage**)a)->pagenumber != (*(TBTMemPage**)b)->pagenumber );
+ return ( (*(TBTMemPage**)a)->pagenumber > (*(TBTMemPage**)b)->pagenumber ) ? 1 : -1;
+}
+
+
int
TBTSync(TBTree *db) {
- u_int32_t i;
int rc=0;
if ( db->readonly || db->npage==0 )
return TBT_OK;
-
- for(i=0; i<db->curpage; i++)
- if ( !db->Cache[i]->issynced )
- rc |= TBTWritePage(db, db->Cache[i]);
+
+ if ( db->npage ) {
+ u_int32_t i, total=0;
+ TBTMemPage *ptr, **data = (TBTMemPage**)tmalloc(db->npage*sizeof(TBTMemPage*)), **pptr;
+ pptr=data;
+ for(i=0; i<HASHSIZE(db->npage); i++) {
+ ptr = db->Cache[i];
+ while(ptr) {
+ if ( !ptr->issynced ) {
+ *pptr = ptr;
+ pptr++;
+ }
+ ptr = ptr->link;
+ }
+ }
+
+ total=pptr-data;
+ if ( total > 0 ) {
+ if ( total>1 )
+ qsort( data, total, sizeof(TBTMemPage*), cmpNPage);
+
+ pptr=data;
+ while( pptr-data<total) {
+ rc |= TBTWritePage(db, *pptr);
+ pptr++;
+ }
+ }
+ tfree(data);
+ }
if ( fsync(db->fd) ) {
tlog(TL_CRIT,"TBTSync: fsync failed: %s",strerror(errno));
- rc=1;
+ rc=TBT_ERROR;
}
return (rc) ? TBT_ERROR : TBT_OK;
}
-static int
-findInCache(TBTree *db, u_int32_t pagenumber, int *pos, TBTMemPage **StopLow, TBTMemPage **StopHigh) {
- TBTMemPage **StopMiddle;
+static TBTMemPage *
+findInCache(TBTree *db, u_int32_t pagenumber) {
+ TBTMemPage *ptr;
- /* Loop invariant: StopLow <= StopMiddle < StopHigh */
- while (StopLow < StopHigh) {
- StopMiddle = StopLow + ( ( StopHigh - StopLow ) >> 1 );
-
- if ( (*StopMiddle)->pagenumber == pagenumber ) {
- *pos = StopMiddle - db->Cache;
- return FOUND;
- } else if ( (*StopMiddle)->pagenumber < pagenumber )
- StopLow = StopMiddle + 1;
- else
- StopHigh = StopMiddle;
+ ptr = db->Cache[ pagenumber % HASHSIZE(db->npage) ];
+
+ while(ptr && ptr->pagenumber != pagenumber)
+ ptr = ptr->link;
+
+ return ptr;;
+}
+
+static void
+removeFromCache(TBTree *db, u_int32_t pagenumber) {
+ TBTMemPage *ptr, *prev=NULL;
+ int pos = pagenumber % HASHSIZE(db->npage);
+
+ ptr = db->Cache[ pos ];
+
+ while(ptr) {
+ if ( ptr->pagenumber == pagenumber ) {
+ if ( prev )
+ prev->link = ptr->link;
+ else
+ db->Cache[ pos ] = ptr->link;
+ break;
+ }
+ prev=ptr;
+ ptr = ptr->link;
}
+}
- *pos = StopHigh - db->Cache;
- return NOTFOUND;
+static void
+insertInCache(TBTree *db, TBTMemPage *page) {
+ int pos = page->pagenumber % HASHSIZE(db->npage);
+
+ page->link = db->Cache[ pos ];
+ db->Cache[ pos ] = page;
}
static TBTMemPage*
-PageAlloc(TBTree *db, int *posincache) {
+PageAlloc(TBTree *db) {
TBTMemPage *page;
- *posincache = -1;
if ( db->curpage < db->npage ) {
- page = db->Cache[db->curpage] = (TBTMemPage*)tmalloc(sizeof(TBTMemPage));
+ page = (TBTMemPage*)tmalloc(sizeof(TBTMemPage));
memset( page, 0, TBTMEMPAGEHDRSZ );
page->iscached=1;
if ( db->curpage == 0 ) {
page->prev = db->TimeCacheLast;
db->TimeCacheLast = page;
}
- *posincache = db->curpage;
db->curpage++;
} else if ( db->npage == 0 ) {
page = (TBTMemPage*)tmalloc(sizeof(TBTMemPage));
while( page->next && page->islocked )
page = page->next;
if ( page==db->TimeCacheLast && page->islocked ) { /*all pages locked*/
- /*tlog(TL_WARN,"TBTReadPage: all pages in cache locked, increase number of cached pages");*/
+ /* tlog(TL_WARN,"TBTReadPage: all pages in cache locked, increase number of cached pages"); */
page = (TBTMemPage*)tmalloc(sizeof(TBTMemPage));
memset( page, 0, TBTMEMPAGEHDRSZ );
} else {
if ( !page->issynced )
if ( TBTWritePage(db, page) )
return NULL;
- if( findInCache(db, page->pagenumber, posincache, db->Cache, db->Cache + db->curpage) != FOUND )
- tlog(TL_CRIT,"PageAlloc: something wrong: no page with pagenumber %d in cache", page->pagenumber);
- memset( page, 0, TBTMEMPAGEHDRSZ );
- page->iscached=1;
+ removeFromCache(db, page->pagenumber);
if ( page != db->TimeCacheLast ) {
- if ( page->prev )
+ if ( page == db->TimeCache ) {
+ db->TimeCache = page->next;
+ db->TimeCache->prev = NULL;
+ } else {
page->prev->next = page->next;
- if ( page->next )
page->next->prev = page->prev;
+ }
+ memset( page, 0, TBTMEMPAGEHDRSZ );
db->TimeCacheLast->next = page;
page->prev = db->TimeCacheLast;
db->TimeCacheLast = page;
- page->next = NULL;
- }
+ } else
+ memset( page, 0, TBTMEMPAGEHDRSZ );
+ page->iscached=1;
}
}
return page;
}
-static void
-findAndMovePN(TBTree *db, TBTMemPage *page, int pos) {
- int newpos;
-
- if ( db->curpage < 2 )
- return;
-
- if ( pos < 0 )
- pos = db->curpage-1;
- tassert( pos < db->curpage && db->Cache[pos]==page );
-
- if ( pos+1 != db->curpage && db->Cache[pos+1]->pagenumber < page->pagenumber ) {
- if ( findInCache(db, page->pagenumber, &newpos, db->Cache + pos + 1, db->Cache + db->curpage )!=NOTFOUND)
- tlog(TL_CRIT,"findAndMovePN: Something wrong, duplicate page with pagenumber %d", page->pagenumber);
- memmove( db->Cache + pos, db->Cache + pos + 1, (newpos-pos-1)*sizeof(TBTMemPage**) );
- db->Cache[newpos-1] = page;
- } else if ( pos!=0 && db->Cache[pos-1]->pagenumber > page->pagenumber ) {
- if( findInCache(db, page->pagenumber, &newpos, db->Cache, db->Cache + pos )!=NOTFOUND);
- tlog(TL_CRIT,"findAndMovePN: Something wrong, duplicate page with pagenumber %d", page->pagenumber);
- memmove( db->Cache + newpos + 1, db->Cache + newpos, (pos-newpos)*sizeof(TBTMemPage**));
- db->Cache[newpos] = page;
- }
-}
-
static int
TBTReadPage(TBTree *db, u_int32_t pagenumber, TBTMemPage **page) {
- int rc, pos=0;
+ int rc;
- if ( findInCache(db, pagenumber, &pos, db->Cache, db->Cache + db->curpage)==FOUND ) {
+ if ( db->npage && (*page=findInCache(db, pagenumber))!=NULL ) {
db->cachehits++;
- *page=db->Cache[pos];
if ( *page != db->TimeCacheLast ) {
- if ( (*page)->prev )
+ if ( (*page) == db->TimeCache ) {
+ db->TimeCache = (*page)->next;
+ db->TimeCache->prev=NULL;
+ } else {
(*page)->prev->next = (*page)->next;
- if ( (*page)->next )
(*page)->next->prev = (*page)->prev;
+ }
db->TimeCacheLast->next = (*page);
(*page)->prev = db->TimeCacheLast;
db->TimeCacheLast = *page;
} else {
off_t offset = (off_t)pagenumber * (off_t)TBTREEPAGESIZE;
- if( (*page = PageAlloc(db, &pos))==NULL )
+ if( (*page = PageAlloc(db))==NULL )
return TBT_ERROR;
if ( lseek(db->fd, offset, SEEK_SET) != offset ) {
(*page)->issynced=1;
(*page)->pagenumber=pagenumber;
if ( (rc=read(db->fd, &( (*page)->page ), TBTREEPAGESIZE)) != TBTREEPAGESIZE ) {
- tlog(TL_CRIT,"TBTReadPage: read failed: %s %d %d",strerror(errno), pagenumber, offset);
+ tlog(TL_CRIT,"TBTReadPage: read failed: %s %d %d",strerror(errno), pagenumber, offset);
return TBT_ERROR;
}
if ( (*page)->iscached )
- findAndMovePN(db, *page, pos);
+ insertInCache(db, *page);
}
db->pageread++;
static int
TBTNewPage(TBTree *db, TBTMemPage **page) {
- int pos;
-
if ( db->lastpagenumber==0 ) {
off_t offset;
if ( (offset=lseek(db->fd, 0, SEEK_END)) < 0 ) {
db->lastpagenumber = offset/TBTREEPAGESIZE;
}
- if( (*page = PageAlloc(db, &pos))==NULL )
+ if( (*page = PageAlloc(db))==NULL )
return TBT_ERROR;
(*page)->pagenumber = db->lastpagenumber;
(*page)->page.freespace = TBTREEPAGESIZE-TBTPAGEHDRSZ;
if ( (*page)->iscached )
- findAndMovePN(db, *page, pos);
+ insertInCache(db, *page);
return TBT_OK;
}