|
|
|
@ -215,7 +215,9 @@ func (t *freezerTable) repair() error { |
|
|
|
|
if t.readonly { |
|
|
|
|
return fmt.Errorf("index file(path: %s, name: %s) size is not a multiple of %d", t.path, t.name, indexEntrySize) |
|
|
|
|
} |
|
|
|
|
truncateFreezerFile(t.index, stat.Size()-overflow) // New file can't trigger this path
|
|
|
|
|
if err := truncateFreezerFile(t.index, stat.Size()-overflow); err != nil { |
|
|
|
|
return err |
|
|
|
|
} // New file can't trigger this path
|
|
|
|
|
} |
|
|
|
|
// Retrieve the file sizes and prepare for truncation
|
|
|
|
|
if stat, err = t.index.Stat(); err != nil { |
|
|
|
@ -260,8 +262,8 @@ func (t *freezerTable) repair() error { |
|
|
|
|
// Print an error log if the index is corrupted due to an incorrect
|
|
|
|
|
// last index item. While it is theoretically possible to have a zero offset
|
|
|
|
|
// by storing all zero-size items, it is highly unlikely to occur in practice.
|
|
|
|
|
if lastIndex.offset == 0 && offsetsSize%indexEntrySize > 1 { |
|
|
|
|
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "items", offsetsSize%indexEntrySize-1) |
|
|
|
|
if lastIndex.offset == 0 && offsetsSize/indexEntrySize > 1 { |
|
|
|
|
log.Error("Corrupted index file detected", "lastOffset", lastIndex.offset, "indexes", offsetsSize/indexEntrySize) |
|
|
|
|
} |
|
|
|
|
if t.readonly { |
|
|
|
|
t.head, err = t.openFile(lastIndex.filenum, openFreezerFileForReadOnly) |
|
|
|
@ -416,6 +418,9 @@ func (t *freezerTable) truncateHead(items uint64) error { |
|
|
|
|
if err := truncateFreezerFile(t.index, int64(length+1)*indexEntrySize); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if err := t.index.Sync(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
// Calculate the new expected size of the data file and truncate it
|
|
|
|
|
var expected indexEntry |
|
|
|
|
if length == 0 { |
|
|
|
@ -438,6 +443,7 @@ func (t *freezerTable) truncateHead(items uint64) error { |
|
|
|
|
// Release any files _after the current head -- both the previous head
|
|
|
|
|
// and any files which may have been opened for reading
|
|
|
|
|
t.releaseFilesAfter(expected.filenum, true) |
|
|
|
|
|
|
|
|
|
// Set back the historic head
|
|
|
|
|
t.head = newHead |
|
|
|
|
t.headId = expected.filenum |
|
|
|
@ -445,6 +451,9 @@ func (t *freezerTable) truncateHead(items uint64) error { |
|
|
|
|
if err := truncateFreezerFile(t.head, int64(expected.offset)); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if err := t.head.Sync(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
// All data files truncated, set internal counters and return
|
|
|
|
|
t.headBytes = int64(expected.offset) |
|
|
|
|
t.items.Store(items) |
|
|
|
@ -589,10 +598,12 @@ func (t *freezerTable) Close() error { |
|
|
|
|
// error on Windows.
|
|
|
|
|
doClose(t.index, true, true) |
|
|
|
|
doClose(t.meta, true, true) |
|
|
|
|
|
|
|
|
|
// The preopened non-head data-files are all opened in readonly.
|
|
|
|
|
// The head is opened in rw-mode, so we sync it here - but since it's also
|
|
|
|
|
// part of t.files, it will be closed in the loop below.
|
|
|
|
|
doClose(t.head, true, false) // sync but do not close
|
|
|
|
|
|
|
|
|
|
for _, f := range t.files { |
|
|
|
|
doClose(f, false, true) // close but do not sync
|
|
|
|
|
} |
|
|
|
|