Browse Source

fsck: If data timestamps are unexpectedly zero, truncate data

This probably means that the file was written, and metadata was journaled,
but the system crashed before data was written.  If that happens, the
end of the file will be zeroed out.  We don't bother checking the entire
file here; if we see just one timestamp that is unexpectedly zero, let's
truncate the data there.
tags/nilmdb-2.2.0
Jim Paris 8 months ago
parent
commit
df4e7f0967
1 changed files with 33 additions and 7 deletions
  1. +33
    -7
      nilmdb/fsck/fsck.py

+ 33
- 7
nilmdb/fsck/fsck.py View File

@@ -512,18 +512,32 @@ class Fsck(object):
match = (ts < stime) | (ts >= etime)
if match.any():
row = numpy.argmax(match)
raise FsckError("%s: data timestamp %d at row %d "
"outside interval range [%d,%d)",
path, ts[row], row + start,
stime, etime)
if ts[row] != 0:
raise FsckError("%s: data timestamp %d at row %d "
"outside interval range [%d,%d)",
path, ts[row], row + start,
stime, etime)

# Timestamp is zero and out of the expected range;
# assume file ends with zeroed data and just truncate it.
self.fix_table_by_truncating(
path, tab, row + start,
"data timestamp is out of range, and zero")

# Verify that timestamps are monotonic
match = numpy.diff(ts) <= 0
if match.any():
row = numpy.argmax(match)
raise FsckError("%s: non-monotonic timestamp (%d -> %d)"
" at row %d", path, ts[row], ts[row+1],
row + start)
if ts[row+1] != 0:
raise FsckError("%s: non-monotonic timestamp (%d -> %d)"
" at row %d", path, ts[row], ts[row+1],
row + start)

# Timestamp is zero and non-monotonic;
# assume file ends with zeroed data and just truncate it.
self.fix_table_by_truncating(
path, tab, row + start + 1,
"data timestamp is non-monotonic, and zero")

first_ts = ts[0]
if last_ts is not None and first_ts <= last_ts:
@@ -542,3 +556,15 @@ class Fsck(object):
done += count
update(done)
return done

def fix_table_by_truncating(self, path, tab, row, reason):
# Simple fix for bad data: truncate the table at the given row.
# On retry, fix_bad_interval will correct the database and timestamps
# to account for this truncation.
msg = f"{path}: bad data in table, starting at row {row}: {reason}"
if not self.fix:
raise FixableFsckError(msg)
err(f"\n{msg}\nWill try truncating table")
(subdir, fname, offs, count) = tab._offset_from_row(row)
tab._remove_or_truncate_file(subdir, fname, offs)
raise RetryFsck

Loading…
Cancel
Save