@@ -129,8 +129,8 @@ func (s *Store[H]) Start(ctx context.Context) error {
129
129
default :
130
130
}
131
131
132
- if err := s .loadHeadAndTail (ctx ); err != nil && ! errors . Is ( err , header . ErrNotFound ) {
133
- return err
132
+ if err := s .init (ctx ); err != nil {
133
+ return fmt . Errorf ( "header/store: initializing: %w" , err )
134
134
}
135
135
136
136
go s .flushLoop ()
@@ -433,6 +433,7 @@ func (s *Store[H]) flushLoop() {
433
433
ctx := context .Background ()
434
434
435
435
flush := func (headers []H ) {
436
+ log .Debug ("flush request" , len (headers ))
436
437
s .ensureInit (headers )
437
438
// add headers to the pending and ensure they are accessible
438
439
s .pending .Append (headers ... )
@@ -557,10 +558,21 @@ func (s *Store[H]) readByKey(ctx context.Context, key datastore.Key) (H, error)
557
558
558
559
var h header.Hash
559
560
if err := h .UnmarshalJSON (b ); err != nil {
561
+ return zero , fmt .Errorf ("unmarshaling header hash at %s key: %w" , key , err )
562
+ }
563
+
564
+ hdr , err := s .Get (ctx , h )
565
+ if err != nil {
566
+ if errors .Is (err , header .ErrNotFound ) {
567
+ derr := s .ds .Delete (ctx , key )
568
+ if derr != nil {
569
+ err = errors .Join (err , fmt .Errorf ("deleting key %s, header for which was not found: %w" , key , derr ))
570
+ }
571
+ }
560
572
return zero , err
561
573
}
562
574
563
- return s . Get ( ctx , h )
575
+ return hdr , nil
564
576
}
565
577
566
578
func (s * Store [H ]) get (ctx context.Context , hash header.Hash ) ([]byte , error ) {
@@ -661,39 +673,53 @@ func (s *Store[H]) nextTail(ctx context.Context) (tail H, changed bool) {
661
673
return tail , changed
662
674
}
663
675
664
- func (s * Store [H ]) loadHeadAndTail (ctx context.Context ) error {
676
+ // init loads the head and tail headers and sets them on the store.
677
+ // allows partial initialization of either tail or head if one of the is not found.
678
+ func (s * Store [H ]) init (ctx context.Context ) error {
665
679
head , err := s .readByKey (ctx , headKey )
666
- if err != nil {
667
- return fmt .Errorf ("header/store: cannot load headKey: %w" , err )
680
+ if err != nil && ! errors .Is (err , header .ErrNotFound ) {
681
+ return fmt .Errorf ("reading headKey: %w" , err )
682
+ }
683
+ if ! head .IsZero () {
684
+ s .contiguousHead .Store (& head )
685
+ s .heightSub .Init (head .Height ())
686
+ log .Debugw ("initialized head" , "height" , head .Height ())
668
687
}
669
688
670
689
tail , err := s .readByKey (ctx , tailKey )
671
- if err != nil {
672
- return fmt .Errorf ("header/store: cannot load tailKey: %w" , err )
690
+ if err != nil && ! errors .Is (err , header .ErrNotFound ) {
691
+ return fmt .Errorf ("reading tailKey: %w" , err )
692
+ }
693
+ if ! tail .IsZero () {
694
+ s .tailHeader .Store (& tail )
695
+ log .Debugw ("initialized tail" , "height" , tail .Height ())
673
696
}
674
697
675
- s .init (head , tail )
676
698
return nil
677
699
}
678
700
701
+ // ensureInit initializes the store with the given headers if it is not already initialized.
679
702
func (s * Store [H ]) ensureInit (headers []H ) {
680
- headExist , tailExist := s .contiguousHead .Load () != nil , s .tailHeader .Load () != nil
681
- if len (headers ) == 0 || (tailExist && headExist ) {
703
+ if len (headers ) == 0 {
682
704
return
683
- } else if tailExist || headExist {
684
- panic ("header/store: head and tail must be both present or absent" )
685
705
}
686
706
687
- tail , head := headers [0 ], headers [len (headers )- 1 ]
688
- s .init (head , tail )
689
- }
707
+ if headPtr := s .contiguousHead .Load (); headPtr == nil {
708
+ head := headers [len (headers )- 1 ]
709
+ if s .contiguousHead .CompareAndSwap (headPtr , & head ) {
710
+ s .heightSub .Init (head .Height ())
711
+ log .Debugw ("initialized head" , "height" , head .Height ())
712
+ }
713
+ }
690
714
691
- func (s * Store [H ]) init (head , tail H ) {
692
- s .contiguousHead .Store (& head )
693
- s .heightSub .Init (head .Height ())
694
- s .tailHeader .Store (& tail )
715
+ if tailPtr := s .tailHeader .Load (); tailPtr == nil {
716
+ tail := headers [0 ]
717
+ s .tailHeader .CompareAndSwap (tailPtr , & tail )
718
+ log .Debugw ("initialized tail" , "height" , tail .Height ())
719
+ }
695
720
}
696
721
722
+ // deinit deinitializes the store.
697
723
func (s * Store [H ]) deinit () {
698
724
s .cache .Purge ()
699
725
s .heightIndex .cache .Purge ()
0 commit comments