Skip to content

Commit b840507

Browse files
martinconicistae
andauthored
fix: delete tag from chunck if tag deleted or not found (#4995)
Co-authored-by: istae <14264581+istae@users.noreply.github.com>
1 parent 00d14c3 commit b840507

File tree

2 files changed

+180
-36
lines changed

2 files changed

+180
-36
lines changed

pkg/storer/internal/upload/uploadstore.go

Lines changed: 57 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,24 @@ func Report(ctx context.Context, st transaction.Store, chunk swarm.Chunk, state
564564

565565
indexStore := st.IndexStore()
566566

567+
deleteFunc := func() error {
568+
// Once the chunk is stored/synced/failed to sync, it is deleted from the upload store as
569+
// we no longer need to keep track of this chunk. We also need to cleanup
570+
// the pushItem.
571+
pi := &pushItem{
572+
Timestamp: ui.Uploaded,
573+
Address: chunk.Address(),
574+
BatchID: chunk.Stamp().BatchID(),
575+
}
576+
577+
return errors.Join(
578+
indexStore.Delete(pi),
579+
chunkstamp.Delete(indexStore, uploadScope, pi.Address, pi.BatchID),
580+
st.ChunkStore().Delete(ctx, chunk.Address()),
581+
indexStore.Delete(ui),
582+
)
583+
}
584+
567585
err := indexStore.Get(ui)
568586
if err != nil {
569587
// because of the nature of the feed mechanism of the uploadstore/pusher, a chunk that is in inflight may be sent more than once to the pusher.
@@ -575,49 +593,52 @@ func Report(ctx context.Context, st transaction.Store, chunk swarm.Chunk, state
575593
return fmt.Errorf("failed to read uploadItem %x: %w", ui.BatchID, err)
576594
}
577595

578-
ti := &TagItem{TagID: ui.TagID}
579-
err = indexStore.Get(ti)
580-
if err != nil {
581-
return fmt.Errorf("failed getting tag: %w", err)
582-
}
583-
584-
switch state {
585-
case storage.ChunkSent:
586-
ti.Sent++
587-
case storage.ChunkStored:
588-
ti.Stored++
589-
// also mark it as synced
590-
fallthrough
591-
case storage.ChunkSynced:
592-
ti.Synced++
593-
case storage.ChunkCouldNotSync:
594-
break
595-
}
596+
if ui.TagID > 0 {
597+
ti := &TagItem{TagID: ui.TagID}
598+
err = indexStore.Get(ti)
599+
if err != nil {
600+
if errors.Is(err, storage.ErrNotFound) { // tag was deleted by user
601+
if state == storage.ChunkSent {
602+
ui.TagID = 0
603+
err = indexStore.Put(ui)
604+
if err != nil {
605+
return fmt.Errorf("failed updating empty tag for chunk: %w", err)
606+
}
607+
608+
return nil
609+
}
610+
611+
// state != sent
612+
return deleteFunc()
613+
614+
} else {
615+
return fmt.Errorf("failed getting tag: %w", err)
616+
}
617+
}
618+
switch state {
619+
case storage.ChunkSent:
620+
ti.Sent++
621+
case storage.ChunkStored:
622+
ti.Stored++
623+
// also mark it as synced
624+
fallthrough
625+
case storage.ChunkSynced:
626+
ti.Synced++
627+
case storage.ChunkCouldNotSync:
628+
break
629+
}
596630

597-
err = indexStore.Put(ti)
598-
if err != nil {
599-
return fmt.Errorf("failed updating tag: %w", err)
631+
err = indexStore.Put(ti)
632+
if err != nil {
633+
return fmt.Errorf("failed updating tag: %w", err)
634+
}
600635
}
601636

602637
if state == storage.ChunkSent {
603638
return nil
604639
}
605640

606-
// Once the chunk is stored/synced/failed to sync, it is deleted from the upload store as
607-
// we no longer need to keep track of this chunk. We also need to cleanup
608-
// the pushItem.
609-
pi := &pushItem{
610-
Timestamp: ui.Uploaded,
611-
Address: chunk.Address(),
612-
BatchID: chunk.Stamp().BatchID(),
613-
}
614-
615-
return errors.Join(
616-
indexStore.Delete(pi),
617-
chunkstamp.Delete(indexStore, uploadScope, pi.Address, pi.BatchID),
618-
st.ChunkStore().Delete(ctx, chunk.Address()),
619-
indexStore.Delete(ui),
620-
)
641+
return deleteFunc()
621642
}
622643

623644
var (

pkg/storer/internal/upload/uploadstore_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -817,6 +817,129 @@ func TestChunkReporter(t *testing.T) {
817817
})
818818
}
819819

820+
func TestDeleteTagReporter(t *testing.T) {
821+
822+
t.Parallel()
823+
824+
ts := newTestStorage(t)
825+
826+
var (
827+
tag upload.TagItem
828+
putter internal.PutterCloserWithReference
829+
err error
830+
)
831+
832+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
833+
tag, err = upload.NextTag(s.IndexStore())
834+
return err
835+
}); err != nil {
836+
t.Fatalf("failed creating tag: %v", err)
837+
}
838+
839+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
840+
putter, err = upload.NewPutter(s.IndexStore(), tag.TagID)
841+
return err
842+
}); err != nil {
843+
t.Fatalf("failed creating putter: %v", err)
844+
}
845+
846+
t.Run("delete tag while uploading", func(t *testing.T) {
847+
848+
chunk := chunktest.GenerateTestRandomChunks(1)[0]
849+
850+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
851+
return putter.Put(context.Background(), s, chunk)
852+
}); err != nil {
853+
t.Fatalf("Put(...): unexpected error: %v", err)
854+
}
855+
856+
report := func(ch swarm.Chunk, state int) {
857+
t.Helper()
858+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
859+
return upload.Report(context.Background(), s, ch, state)
860+
}); err != nil {
861+
t.Fatalf("Report(...): unexpected error: %v", err)
862+
}
863+
}
864+
865+
tagItem := &upload.TagItem{TagID: tag.TagID}
866+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
867+
return s.IndexStore().Get(tagItem)
868+
}); err != nil {
869+
t.Fatalf("Get(...): unexpected error: %v", err)
870+
}
871+
872+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
873+
return s.IndexStore().Delete(tagItem)
874+
}); err != nil {
875+
t.Fatalf("Put(...): unexpected error: %v", err)
876+
}
877+
878+
t.Run("mark sent", func(t *testing.T) {
879+
report(chunk, storage.ChunkSent)
880+
})
881+
882+
t.Run("verify internal state", func(t *testing.T) {
883+
884+
ui := &upload.UploadItem{Address: chunk.Address(), BatchID: chunk.Stamp().BatchID()}
885+
err := ts.IndexStore().Get(ui)
886+
if err != nil {
887+
t.Fatalf("Report(...): unexpected error: %v", err)
888+
}
889+
890+
if diff := cmp.Diff(uint64(0), ui.TagID); diff != "" {
891+
t.Fatalf("Get(...): unexpected TagItem (-want +have):\n%s", diff)
892+
}
893+
})
894+
})
895+
896+
t.Run("delete tag while uploading and not sent", func(t *testing.T) {
897+
// Generate a chunk.
898+
chunk := chunktest.GenerateTestRandomChunks(1)[0]
899+
900+
// Store the chunk (which creates the uploadItem).
901+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
902+
return putter.Put(context.Background(), s, chunk)
903+
}); err != nil {
904+
t.Fatalf("Put(...): unexpected error: %v", err)
905+
}
906+
907+
// Confirm the upload item exists.
908+
ui := &upload.UploadItem{
909+
Address: chunk.Address(),
910+
BatchID: chunk.Stamp().BatchID(),
911+
}
912+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
913+
return s.IndexStore().Get(ui)
914+
}); err != nil {
915+
t.Fatalf("Get(...): unexpected error: %v", err)
916+
}
917+
918+
// Delete the tag item to simulate a user deleting it.
919+
tagItem := &upload.TagItem{TagID: tag.TagID}
920+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
921+
return s.IndexStore().Delete(tagItem)
922+
}); err != nil {
923+
t.Fatalf("Delete(...): unexpected error: %v", err)
924+
}
925+
926+
// Now report with a state other than ChunkSent, e.g. ChunkStored.
927+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
928+
return upload.Report(context.Background(), s, chunk, storage.ChunkStored)
929+
}); err != nil {
930+
t.Fatalf("Report(...): unexpected error: %v", err)
931+
}
932+
933+
// Verify that the upload item was deleted (cleanup via deleteFunc).
934+
if err := ts.Run(context.Background(), func(s transaction.Store) error {
935+
return s.IndexStore().Get(ui)
936+
}); !errors.Is(err, storage.ErrNotFound) {
937+
t.Fatalf("expected uploadItem to be deleted, got error: %v", err)
938+
}
939+
})
940+
941+
}
942+
820943
func TestNextTagID(t *testing.T) {
821944
t.Parallel()
822945

0 commit comments

Comments
 (0)