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