From: ian Date: Wed, 25 Jan 2006 23:18:04 +0000 (+0000) Subject: new compaction entrypoints impl'd X-Git-Tag: debian/1.1.1~77 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?p=chiark-tcl.git;a=commitdiff_plain;h=2b24ccf8dc74b52fad1d1a74f29c5d3fe493d68a new compaction entrypoints impl'd --- diff --git a/cdb/cdb.tct b/cdb/cdb.tct index e33607b..d113af9 100644 --- a/cdb/cdb.tct +++ b/cdb/cdb.tct @@ -106,7 +106,7 @@ Table cdbwr Cdbwr_SubCommand db iddata(&cdbtcl_rwdatabases) compact-check 0 db iddata(&cdbtcl_rwdatabases) - compact-onupdate 0 # this is the default + compact-auto 0 # this is the default db iddata(&cdbtcl_rwdatabases) compact-explicit 0 db iddata(&cdbtcl_rwdatabases) diff --git a/cdb/writeable.c b/cdb/writeable.c index 4230e62..0334a45 100644 --- a/cdb/writeable.c +++ b/cdb/writeable.c @@ -140,7 +140,6 @@ typedef struct Rw { int ix, autocompact; int cdb_fd, lock_fd; struct cdb cdb; /* valid iff cdb_fd >= 0 */ - off_t cdb_bytes; /* valid iff cdb_fd >= 0 */ FILE *logfile; HashTable logincore; Pathbuf pbsome, pbother; @@ -153,6 +152,7 @@ static int rw_close(Tcl_Interp *ip, Rw *rw) { rc= TCL_OK; ht_destroy(&rw->logincore); + if (rw->cdb_fd >= 0) cdb_free(&rw->cdb); maybe_close(rw->cdb_fd); maybe_close(rw->lock_fd); @@ -358,6 +358,19 @@ static int infocb(Tcl_Interp *ip, Rw *rw, const char *arg1, /*---------- Opening ----------*/ +static int cdbinit(Tcl_Interp *ip, Rw *rw) { + /* On entry, cdb_fd >=0 but cdb is _undefined_/ + * On exit, either cdb_fd<0 or cdb is initialised */ + int r, rc; + + r= cdb_init(&rw->cdb, rw->cdb_fd); + if (r) { + rc= cht_posixerr(ip, errno, "failed to initialise cdb reader"); + close(rw->cdb_fd); rw->cdb_fd= -1; return rc; + } + return TCL_OK; +} + int cht_do_cdbwr_open(ClientData cd, Tcl_Interp *ip, const char *pathb, Tcl_Obj *on_info, Tcl_Obj *on_lexminval, void **result) { @@ -392,11 +405,7 @@ int cht_do_cdbwr_open(ClientData cd, Tcl_Interp *ip, const char *pathb, rw->cdb_fd= open(pathbuf_sfx(&rw->pbsome,".cdb"), O_RDONLY); if (rw->cdb_fd >=0) { - r= cdb_init(&rw->cdb, rw->cdb_fd); - if (r) { - rc= cht_posixerr(ip, errno, "failed to initialise cdb reader"); - close(rw->cdb_fd); rw->cdb_fd= -1; goto x_rc; - } + rc= cdbinit(ip, rw); if (rc) goto x_rc; } else if (errno == ENOENT) { if (rw->mainsz) { rc= cht_staticerr(ip, ".cdb does not exist but .main is nonempty -" @@ -474,7 +483,7 @@ int cht_do_cdbwr_open(ClientData cd, Tcl_Interp *ip, const char *pathb, return rc; } -/*==================== COMPACTING ====================*/ +/*==================== COMPACTION ====================*/ struct ht_forall_ctx { struct cdb_make cdbm; @@ -527,7 +536,7 @@ static int addto_main(const char *key, HashValue *val, /*---------- compact main entrypoint ----------*/ -static int compact_core(Tcl_Interp *ip, Rw *rw, unsigned long logsize, +static int compact_core(Tcl_Interp *ip, Rw *rw, unsigned long logsz, long *reccount_r) { /* creates new .cdb and .main * closes logfile @@ -554,7 +563,7 @@ static int compact_core(Tcl_Interp *ip, Rw *rw, unsigned long logsize, rw->logfile= 0; rc= infocb(ip, rw, "compact-start", "log=%luby main=%luby", - logsize, (unsigned long)rw->mainsz); + logsz, (unsigned long)rw->mainsz); if (rc) goto x_rc; if (rw->on_lexminval.llength) { @@ -655,16 +664,18 @@ static int compact_core(Tcl_Interp *ip, Rw *rw, unsigned long logsize, /* done! */ - rc= infocb(ip, rw, "compact-end", "log=%luby main=%luby nrecs=%l", - logsize, (unsigned long)rw->mainsz, *a.reccount); + rc= infocb(ip, rw, "compact-end", "main=%luby nrecs=%l", + (unsigned long)rw->mainsz, *a.reccount); if (rc) goto x_rc; - rc= TCL_OK; + return rc; + x_rc: if (a.mainfile) fclose(a.mainfile); if (cdbmaking) cdb_make_finish(&a.cdbm); maybe_close(cdbfd); remove(pathbuf_sfx(&rw->pbsome,".tmp")); /* for tidyness */ + return rc; } /*---------- Closing ----------*/ @@ -716,4 +727,59 @@ int cht_do_cdbwr_close(ClientData cd, Tcl_Interp *ip, void *rw_v) { return rc; } -/*==================== Other entrypoints ====================*/ +/*---------- Other compaction-related entrypoints ----------*/ + +static int compact_keeopen(Tcl_Interp *ip, Rw *rw, int force) { + off_t logsz; + long reccount; + int rc, r; + + logsz= ftello(rw->logfile); + if (logsz < 0) return cht_posixerr(ip, errno, "ftell .log" + " during compact check or force"); + + if (!force && logsz < rw->mainsz / 10 + 1000) return TCL_OK; + + rc= compact_core(ip, rw, logsz, &reccount); if (rc) goto x_rc; + + maybe_close(rw->cdb_fd); + rw->cdb_fd= -1; + ht_destroy(&rw->logincore); + ht_setup(&rw->logincore); + + rw->cdb_fd= open(pathbuf_sfx(&rw->pbsome,".cdb"), O_RDONLY); + if (rw->cdb_fd < 0) PE("reopen .cdb after compact"); + + rc= cdbinit(ip, rw); if (rc) goto x_rc; + + rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".log"), "w"); + if (!rw->logfile) PE("reopen .log after compact"); + + r= fsync(fileno(rw->logfile)); if (r) PE("fsync .log after compact reopen"); + + return TCL_OK; + +x_rc: + /* doom! all updates fail after this (because rw->logfile is 0), and + * we may be usin a lot more RAM than would be ideal. Program will + * have to reopen if it really wants sanity. */ + return rc; +} + +int cht_do_cdbwr_compact_force(ClientData cd, Tcl_Interp *ip, void *rw_v) { + return compact_keeopen(ip, rw_v, 1); +} +int cht_do_cdbwr_compact_check(ClientData cd, Tcl_Interp *ip, void *rw_v) { + return compact_keeopen(ip, rw_v, 0); +} + +int cht_do_cdbwr_compact_explicit(ClientData cd, Tcl_Interp *ip, void *rw_v) { + Rw *rw= rw_v; + rw->autocompact= 0; + return TCL_OK; +} +int cht_do_cdbwr_compact_auto(ClientData cd, Tcl_Interp *ip, void *rw_v) { + Rw *rw= rw_v; + rw->autocompact= 1; + return TCL_OK; +}