Skip to content

Commit e7dcb21

Browse files
wangyifanrjl493456442
authored andcommitted
core/rawdb: implement size reporting for live items in freezer_table (28525)
This is the fix to issue ethereum#27483. A new hiddenBytes() is introduced to calculate the byte size of hidden items in the freezer table. When reporting the size of the freezer table, size of the hidden items will be subtracted from the total size. --------- Co-authored-by: Yifan <Yifan Wang> Co-authored-by: Gary Rong <[email protected]>
1 parent 32633bb commit e7dcb21

File tree

2 files changed

+62
-10
lines changed

2 files changed

+62
-10
lines changed

core/rawdb/freezer_table.go

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,20 @@ func (t *freezerTable) truncateHead(items uint64) error {
467467
return nil
468468
}
469469

470+
// sizeHidden returns the total data size of hidden items in the freezer table.
471+
// This function assumes the lock is already held.
472+
func (t *freezerTable) sizeHidden() (uint64, error) {
473+
hidden, offset := t.itemHidden.Load(), t.itemOffset.Load()
474+
if hidden <= offset {
475+
return 0, nil
476+
}
477+
indices, err := t.getIndices(hidden-1, 1)
478+
if err != nil {
479+
return 0, err
480+
}
481+
return uint64(indices[1].offset), nil
482+
}
483+
470484
// truncateTail discards any recent data before the provided threshold number.
471485
func (t *freezerTable) truncateTail(items uint64) error {
472486
t.lock.Lock()
@@ -495,6 +509,12 @@ func (t *freezerTable) truncateTail(items uint64) error {
495509
newTail.unmarshalBinary(buffer)
496510
newTailId = newTail.filenum
497511
}
512+
// Save the old size for metrics tracking. This needs to be done
513+
// before any updates to either itemHidden or itemOffset.
514+
oldSize, err := t.sizeNolock()
515+
if err != nil {
516+
return err
517+
}
498518
// Update the virtual tail marker and hidden these entries in table.
499519
t.itemHidden.Store(items)
500520
if err := writeMetadata(t.meta, newMetadata(items)); err != nil {
@@ -509,18 +529,12 @@ func (t *freezerTable) truncateTail(items uint64) error {
509529
if t.tailId > newTailId {
510530
return fmt.Errorf("invalid index, tail-file %d, item-file %d", t.tailId, newTailId)
511531
}
512-
// Hidden items exceed the current tail file, drop the relevant
513-
// data files. We need to truncate, save the old size for metrics
514-
// tracking.
515-
oldSize, err := t.sizeNolock()
516-
if err != nil {
517-
return err
518-
}
519532
// Count how many items can be deleted from the file.
520533
var (
521534
newDeleted = items
522535
deleted = t.itemOffset.Load()
523536
)
537+
// Hidden items exceed the current tail file, drop the relevant data files.
524538
for current := items - 1; current >= deleted; current -= 1 {
525539
if _, err := t.index.ReadAt(buffer, int64((current-deleted+1)*indexEntrySize)); err != nil {
526540
return err
@@ -680,6 +694,7 @@ func (t *freezerTable) releaseFilesBefore(num uint32, remove bool) {
680694
func (t *freezerTable) getIndices(from, count uint64) ([]*indexEntry, error) {
681695
// Apply the table-offset
682696
from = from - t.itemOffset.Load()
697+
683698
// For reading N items, we need N+1 indices.
684699
buffer := make([]byte, (count+1)*indexEntrySize)
685700
if _, err := t.index.ReadAt(buffer, int64(from*indexEntrySize)); err != nil {
@@ -870,14 +885,18 @@ func (t *freezerTable) size() (uint64, error) {
870885
return t.sizeNolock()
871886
}
872887

873-
// sizeNolock returns the total data size in the freezer table without obtaining
874-
// the mutex first.
888+
// sizeNolock returns the total data size in the freezer table. This function
889+
// assumes the lock is already held.
875890
func (t *freezerTable) sizeNolock() (uint64, error) {
876891
stat, err := t.index.Stat()
877892
if err != nil {
878893
return 0, err
879894
}
880-
total := uint64(t.maxFileSize)*uint64(t.headId-t.tailId) + uint64(t.headBytes) + uint64(stat.Size())
895+
hidden, err := t.sizeHidden()
896+
if err != nil {
897+
return 0, err
898+
}
899+
total := uint64(t.maxFileSize)*uint64(t.headId-t.tailId) + uint64(t.headBytes) + uint64(stat.Size()) - hidden
881900
return total, nil
882901
}
883902

core/rawdb/freezer_table_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,13 @@ func TestFreezerOffset(t *testing.T) {
658658
}
659659
}
660660

661+
func assertTableSize(t *testing.T, f *freezerTable, size int) {
662+
t.Helper()
663+
if got, err := f.size(); got != uint64(size) {
664+
t.Fatalf("expected size of %d bytes, got %d, err: %v", size, got, err)
665+
}
666+
}
667+
661668
func TestTruncateTail(t *testing.T) {
662669
t.Parallel()
663670
rm, wm, sg := metrics.NewMeter(), metrics.NewMeter(), metrics.NewGauge()
@@ -692,6 +699,9 @@ func TestTruncateTail(t *testing.T) {
692699
5: getChunk(20, 0xaa),
693700
6: getChunk(20, 0x11),
694701
})
702+
// maxFileSize*fileCount + headBytes + indexFileSize - hiddenBytes
703+
expected := 20*7 + 48 - 0
704+
assertTableSize(t, f, expected)
695705

696706
// truncate single element( item 0 ), deletion is only supported at file level
697707
f.truncateTail(1)
@@ -707,6 +717,8 @@ func TestTruncateTail(t *testing.T) {
707717
5: getChunk(20, 0xaa),
708718
6: getChunk(20, 0x11),
709719
})
720+
expected = 20*7 + 48 - 20
721+
assertTableSize(t, f, expected)
710722

711723
// Reopen the table, the deletion information should be persisted as well
712724
f.Close()
@@ -739,6 +751,8 @@ func TestTruncateTail(t *testing.T) {
739751
5: getChunk(20, 0xaa),
740752
6: getChunk(20, 0x11),
741753
})
754+
expected = 20*5 + 36 - 0
755+
assertTableSize(t, f, expected)
742756

743757
// Reopen the table, the above testing should still pass
744758
f.Close()
@@ -760,6 +774,23 @@ func TestTruncateTail(t *testing.T) {
760774
6: getChunk(20, 0x11),
761775
})
762776

777+
// truncate 3 more elements( item 2, 3, 4), the file 1 should be deleted
778+
// file 2 should only contain item 5
779+
f.truncateTail(5)
780+
checkRetrieveError(t, f, map[uint64]error{
781+
0: errOutOfBounds,
782+
1: errOutOfBounds,
783+
2: errOutOfBounds,
784+
3: errOutOfBounds,
785+
4: errOutOfBounds,
786+
})
787+
checkRetrieve(t, f, map[uint64][]byte{
788+
5: getChunk(20, 0xaa),
789+
6: getChunk(20, 0x11),
790+
})
791+
expected = 20*3 + 24 - 20
792+
assertTableSize(t, f, expected)
793+
763794
// truncate all, the entire freezer should be deleted
764795
f.truncateTail(7)
765796
checkRetrieveError(t, f, map[uint64]error{
@@ -771,6 +802,8 @@ func TestTruncateTail(t *testing.T) {
771802
5: errOutOfBounds,
772803
6: errOutOfBounds,
773804
})
805+
expected = 12
806+
assertTableSize(t, f, expected)
774807
}
775808

776809
func TestTruncateHead(t *testing.T) {

0 commit comments

Comments
 (0)