int ix, autocompact;
int cdb_fd, lock_fd;
struct cdb cdb; /* valid iff cdb_fd >= 0 */
- FILE *logfile;
+ FILE *logfile; /* may be 0; if so, is broken */
HashTable logincore;
Pathbuf pbsome, pbother;
off_t mainsz;
a.reccount= reccount_r;
r= fclose(rw->logfile);
+ rw->logfile= 0;
if (r) { rc= cht_posixerr(ip, errno, "probable data loss! failed to fclose"
" logfile during compact"); goto x_rc; }
- rw->logfile= 0;
rc= infocb(ip, rw, "compact-start", "log=%luby main=%luby",
logsz, (unsigned long)rw->mainsz);
static int update(Tcl_Interp *ip, Rw *rw, const char *key,
const Byte *data, int dlen) {
HashValue *val;
+ const char *failed;
int rc, r;
+ off_t recstart;
if (strlen(key) >= KEYLEN_MAX)
return cht_staticerr(ip, "key too long", "CDB KEYOVERFLOW");
if (!rw->logfile) return cht_staticerr
- (ip, "previous compact failed; cdbwr must be closed and reopened "
- "before any further updates", "CDB BROKEN");
+ (ip, "failure during previous compact or error recovery;"
+ " cdbwr must be closed and reopened before any further updates",
+ "CDB BROKEN");
+ recstart= ftello(rw->logfile);
+ if (recstart < 0)
+ return cht_posixerr(ip, errno, "failed to ftello .jrn during update");
+
val= htv_prep(dlen); assert(val);
memcpy(htv_fillptr(val), data, dlen);
x_rc:
TFREE(val);
+ assert(rc);
+
+ /* Now, we have to try to sort out the journal so that it's
+ * truncated and positioned to where this abortively-written record
+ * started, with no buffered output and the error indicator clear.
+ *
+ * There seems to be no portable way to ensure the buffered unwritten
+ * output is discarded, so we close and reopen the stream.
+ */
+ fclose(rw->logfile);
+
+ rw->logfile= fopen(pathbuf_sfx(&rw->pbsome,".jrn"), "r+");
+ if (!rw->logfile) { failed= "fopen"; goto reset_fail; }
+
+ r= ftruncate(fileno(rw->logfile), recstart);
+ if (r) { failed= "ftruncate"; goto reset_fail; }
+
+ r= fseeko(rw->logfile, recstart, SEEK_SET);
+ if (r) { failed= "fseeko"; goto reset_fail; }
+
+ return rc;
+
+ reset_fail:
+ Tcl_AppendResult(ip, " (additionally, ", failed, " failed"
+ " in error recovery: ", strerror(errno), ")", (char*)0);
+ if (rw->logfile) { fclose(rw->logfile); rw->logfile= 0; }
+
return rc;
}
Bugfixes:
* Do not adns_cancel in the middle of adns_forallqueries.
+ * cdb: When cdbwr update writerecord fails, try to recover the
+ situation to sanity so we don't corrupt the log later; if this
+ fails, mark the cdb broken.
* strlen returns size_t, not int; fixed up everywhere relevant.
Closes #393970. (Bug exists only where int and ssize_t differ.)
* Use correct errno value for error writing to new .main during compact.
+ * Do not coredump if fclose journal fails during compact.
Portability fixes:
* Remove unecessary assertion of val<=0xffffffffUL where uint32_t val;