@@ -78,7 +78,7 @@ type Freezer struct {
7878//
7979// The 'tables' argument defines the data tables. If the value of a map
8080// entry is true, snappy compression is disabled for the table.
81- func NewFreezer (datadir string , namespace string , readonly bool , maxTableSize uint32 , tables map [string ]bool ) (* Freezer , error ) {
81+ func NewFreezer (datadir string , namespace string , readonly bool , maxTableSize uint32 , tables map [string ]freezerTableConfig ) (* Freezer , error ) {
8282 // Create the initial freezer object
8383 var (
8484 readMeter = metrics .NewRegisteredMeter (namespace + "ancient/read" , nil )
@@ -121,8 +121,8 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui
121121 }
122122
123123 // Create the tables.
124- for name , disableSnappy := range tables {
125- table , err := newTable (datadir , name , readMeter , writeMeter , sizeGauge , maxTableSize , disableSnappy , readonly )
124+ for name , config := range tables {
125+ table , err := newTable (datadir , name , readMeter , writeMeter , sizeGauge , maxTableSize , config , readonly )
126126 if err != nil {
127127 for _ , table := range freezer .tables {
128128 table .Close ()
@@ -301,7 +301,8 @@ func (f *Freezer) TruncateHead(items uint64) (uint64, error) {
301301 return oitems , nil
302302}
303303
304- // TruncateTail discards any recent data below the provided threshold number.
304+ // TruncateTail discards all data below the specified threshold. Note that only
305+ // 'prunable' tables will be truncated.
305306func (f * Freezer ) TruncateTail (tail uint64 ) (uint64 , error ) {
306307 if f .readonly {
307308 return 0 , errReadOnly
@@ -314,8 +315,10 @@ func (f *Freezer) TruncateTail(tail uint64) (uint64, error) {
314315 return old , nil
315316 }
316317 for _ , table := range f .tables {
317- if err := table .truncateTail (tail ); err != nil {
318- return 0 , err
318+ if table .config .prunable {
319+ if err := table .truncateTail (tail ); err != nil {
320+ return 0 , err
321+ }
319322 }
320323 }
321324 f .tail .Store (tail )
@@ -343,56 +346,77 @@ func (f *Freezer) validate() error {
343346 return nil
344347 }
345348 var (
346- head uint64
347- tail uint64
348- name string
349+ head uint64
350+ prunedTail * uint64
349351 )
350- // Hack to get boundary of any table
351- for kind , table := range f .tables {
352+ // get any head value
353+ for _ , table := range f .tables {
352354 head = table .items .Load ()
353- tail = table .itemHidden .Load ()
354- name = kind
355355 break
356356 }
357- // Now check every table against those boundaries.
358357 for kind , table := range f .tables {
358+ // all tables have to have the same head
359359 if head != table .items .Load () {
360- return fmt .Errorf ("freezer tables %s and %s have differing head: %d != %d" , kind , name , table .items .Load (), head )
360+ return fmt .Errorf ("freezer table %s has a differing head: %d != %d" , kind , table .items .Load (), head )
361361 }
362- if tail != table .itemHidden .Load () {
363- return fmt .Errorf ("freezer tables %s and %s have differing tail: %d != %d" , kind , name , table .itemHidden .Load (), tail )
362+ if ! table .config .prunable {
363+ // non-prunable tables have to start at 0
364+ if table .itemHidden .Load () != 0 {
365+ return fmt .Errorf ("non-prunable freezer table '%s' has a non-zero tail: %d" , kind , table .itemHidden .Load ())
366+ }
367+ } else {
368+ // prunable tables have to have the same length
369+ if prunedTail == nil {
370+ tmp := table .itemHidden .Load ()
371+ prunedTail = & tmp
372+ }
373+ if * prunedTail != table .itemHidden .Load () {
374+ return fmt .Errorf ("freezer table %s has differing tail: %d != %d" , kind , table .itemHidden .Load (), * prunedTail )
375+ }
364376 }
365377 }
378+
379+ if prunedTail == nil {
380+ tmp := uint64 (0 )
381+ prunedTail = & tmp
382+ }
383+
366384 f .frozen .Store (head )
367- f .tail .Store (tail )
385+ f .tail .Store (* prunedTail )
368386 return nil
369387}
370388
371389// repair truncates all data tables to the same length.
372390func (f * Freezer ) repair () error {
373391 var (
374- head = uint64 (math .MaxUint64 )
375- tail = uint64 (0 )
392+ head = uint64 (math .MaxUint64 )
393+ prunedTail = uint64 (0 )
376394 )
395+ // get the minimal head and the maximum tail
377396 for _ , table := range f .tables {
378- items := table .items .Load ()
379- if head > items {
380- head = items
381- }
382- hidden := table .itemHidden .Load ()
383- if hidden > tail {
384- tail = hidden
385- }
397+ head = min (head , table .items .Load ())
398+ prunedTail = max (prunedTail , table .itemHidden .Load ())
386399 }
387- for _ , table := range f .tables {
400+ // apply the pruning
401+ for kind , table := range f .tables {
402+ // all tables need to have the same head
388403 if err := table .truncateHead (head ); err != nil {
389404 return err
390405 }
391- if err := table .truncateTail (tail ); err != nil {
392- return err
406+ if ! table .config .prunable {
407+ // non-prunable tables have to start at 0
408+ if table .itemHidden .Load () != 0 {
409+ panic (fmt .Sprintf ("non-prunable freezer table %s has non-zero tail: %v" , kind , table .itemHidden .Load ()))
410+ }
411+ } else {
412+ // prunable tables have to have the same length
413+ if err := table .truncateTail (prunedTail ); err != nil {
414+ return err
415+ }
393416 }
394417 }
418+
395419 f .frozen .Store (head )
396- f .tail .Store (tail )
420+ f .tail .Store (prunedTail )
397421 return nil
398422}
0 commit comments