forked from cerc-io/plugeth
core/rawdb: fsync head data file before closing it (#26490)
This PR fixes an issue which might result in data lost in freezer. Whenever mutation happens in freezer, all data will be written into head data file and it will be rotated with a new one in case the size of file reaches the threshold. Theoretically, the rotated old data file should be fsync'd to prevent data loss. In freezer.Sync function, we only fsync: (1) index file (2) meta file and (3) head data file. So this PR forcibly fsync the head data file if mutation happens in the boundary of data file.
This commit is contained in:
parent
a21e963ac2
commit
e04d63ebd3
@ -86,14 +86,14 @@ func (f *chainFreezer) Close() error {
|
|||||||
// This functionality is deliberately broken off from block importing to avoid
|
// This functionality is deliberately broken off from block importing to avoid
|
||||||
// incurring additional data shuffling delays on block propagation.
|
// incurring additional data shuffling delays on block propagation.
|
||||||
func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
|
||||||
nfdb := &nofreezedb{KeyValueStore: db}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
backoff bool
|
backoff bool
|
||||||
triggered chan struct{} // Used in tests
|
triggered chan struct{} // Used in tests
|
||||||
|
nfdb = &nofreezedb{KeyValueStore: db}
|
||||||
)
|
)
|
||||||
timer := time.NewTimer(freezerRecheckInterval)
|
timer := time.NewTimer(freezerRecheckInterval)
|
||||||
defer timer.Stop()
|
defer timer.Stop()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-f.quit:
|
case <-f.quit:
|
||||||
|
@ -852,8 +852,11 @@ func (t *freezerTable) advanceHead() error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Commit the contents of the old file to stable storage and
|
||||||
// Close old file, and reopen in RDONLY mode.
|
// tear it down. It will be re-opened in read-only mode.
|
||||||
|
if err := t.head.Sync(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
t.releaseFile(t.headId)
|
t.releaseFile(t.headId)
|
||||||
t.openFile(t.headId, openFreezerFileForReadOnly)
|
t.openFile(t.headId, openFreezerFileForReadOnly)
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ func TestFreezerConcurrentModifyTruncate(t *testing.T) {
|
|||||||
|
|
||||||
var item = make([]byte, 256)
|
var item = make([]byte, 256)
|
||||||
|
|
||||||
for i := 0; i < 1000; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
// First reset and write 100 items.
|
// First reset and write 100 items.
|
||||||
if err := f.TruncateHead(0); err != nil {
|
if err := f.TruncateHead(0); err != nil {
|
||||||
t.Fatal("truncate failed:", err)
|
t.Fatal("truncate failed:", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user