github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/compact_test.go (about) 1 // Copyright 2023 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package storer_test 6 7 import ( 8 "bytes" 9 "context" 10 "testing" 11 "time" 12 13 "github.com/ethersphere/bee/v2/pkg/postage" 14 postagetesting "github.com/ethersphere/bee/v2/pkg/postage/testing" 15 pullerMock "github.com/ethersphere/bee/v2/pkg/puller/mock" 16 chunk "github.com/ethersphere/bee/v2/pkg/storage/testing" 17 "github.com/ethersphere/bee/v2/pkg/storer" 18 "github.com/ethersphere/bee/v2/pkg/swarm" 19 ) 20 21 // TestCompact creates two batches and puts chunks belonging to both batches. 22 // The first batch is then expired, causing free slots to accumulate in sharky. 23 // Next, sharky is compacted, after which, it is tested that valid chunks can still be retrieved. 24 func TestCompact(t *testing.T) { 25 t.Parallel() 26 27 baseAddr := swarm.RandAddress(t) 28 ctx := context.Background() 29 basePath := t.TempDir() 30 31 opts := dbTestOps(baseAddr, 10_000, nil, nil, time.Minute) 32 opts.CacheCapacity = 0 33 34 st, err := storer.New(ctx, basePath, opts) 35 if err != nil { 36 t.Fatal(err) 37 } 38 st.StartReserveWorker(ctx, pullerMock.NewMockRateReporter(0), networkRadiusFunc(0)) 39 40 var chunks []swarm.Chunk 41 batches := []*postage.Batch{postagetesting.MustNewBatch(), postagetesting.MustNewBatch(), postagetesting.MustNewBatch()} 42 evictBatch := batches[1] 43 44 putter := st.ReservePutter() 45 46 for b := 0; b < len(batches); b++ { 47 for i := uint64(0); i < 100; i++ { 48 ch := chunk.GenerateTestRandomChunk() 49 ch = ch.WithStamp(postagetesting.MustNewBatchStamp(batches[b].ID)) 50 chunks = append(chunks, ch) 51 err := putter.Put(ctx, ch) 52 if err != nil { 53 t.Fatal(err) 54 } 55 } 56 } 57 58 c, unsub := st.Events().Subscribe("batchExpiryDone") 59 t.Cleanup(unsub) 60 61 err = st.EvictBatch(ctx, evictBatch.ID) 62 if err != nil { 63 t.Fatal(err) 64 } 65 <-c 66 67 time.Sleep(time.Second) 68 69 if err := st.Close(); err != nil { 70 t.Fatal(err) 71 } 72 73 err = storer.Compact(ctx, basePath, opts, true) 74 if err != nil { 75 t.Fatal(err) 76 } 77 78 st, err = storer.New(ctx, basePath, opts) 79 if err != nil { 80 t.Fatal(err) 81 } 82 83 putter = st.ReservePutter() 84 for i := uint64(0); i < 100; i++ { 85 ch := chunk.GenerateTestRandomChunk() 86 ch = ch.WithStamp(postagetesting.MustNewBatchStamp(batches[0].ID)) 87 chunks = append(chunks, ch) 88 err := putter.Put(ctx, ch) 89 if err != nil { 90 t.Fatal(err) 91 } 92 } 93 94 for _, ch := range chunks { 95 stampHash, err := ch.Stamp().Hash() 96 if err != nil { 97 t.Fatal(err) 98 } 99 has, err := st.ReserveHas(ch.Address(), ch.Stamp().BatchID(), stampHash) 100 if err != nil { 101 t.Fatal(err) 102 } 103 104 if bytes.Equal(ch.Stamp().BatchID(), evictBatch.ID) { 105 if has { 106 t.Fatal("store should NOT have chunk") 107 } 108 checkSaved(t, st, ch, false, false) 109 } else if !has { 110 t.Fatal("store should have chunk") 111 } else { 112 checkSaved(t, st, ch, true, true) 113 } 114 } 115 116 if err := st.Close(); err != nil { 117 t.Fatal(err) 118 } 119 } 120 121 // TestCompactNoEvictions compacts a store that has no free slots to ensure that no chunks get lost. 122 func TestCompactNoEvictions(t *testing.T) { 123 t.Parallel() 124 125 baseAddr := swarm.RandAddress(t) 126 ctx := context.Background() 127 basePath := t.TempDir() 128 129 opts := dbTestOps(baseAddr, 10_000, nil, nil, time.Minute) 130 opts.CacheCapacity = 0 131 132 st, err := storer.New(ctx, basePath, opts) 133 if err != nil { 134 t.Fatal(err) 135 } 136 st.StartReserveWorker(ctx, pullerMock.NewMockRateReporter(0), networkRadiusFunc(0)) 137 138 var chunks []swarm.Chunk 139 batches := []*postage.Batch{postagetesting.MustNewBatch(), postagetesting.MustNewBatch(), postagetesting.MustNewBatch()} 140 141 putter := st.ReservePutter() 142 143 for b := 0; b < len(batches); b++ { 144 for i := uint64(0); i < 100; i++ { 145 ch := chunk.GenerateTestRandomChunk() 146 ch = ch.WithStamp(postagetesting.MustNewBatchStamp(batches[b].ID)) 147 chunks = append(chunks, ch) 148 err := putter.Put(ctx, ch) 149 if err != nil { 150 t.Fatal(err) 151 } 152 } 153 } 154 155 if err := st.Close(); err != nil { 156 t.Fatal(err) 157 } 158 159 err = storer.Compact(ctx, basePath, opts, false) 160 if err != nil { 161 t.Fatal(err) 162 } 163 164 st, err = storer.New(ctx, basePath, opts) 165 if err != nil { 166 t.Fatal(err) 167 } 168 169 putter = st.ReservePutter() 170 for i := uint64(0); i < 100; i++ { 171 ch := chunk.GenerateTestRandomChunk() 172 ch = ch.WithStamp(postagetesting.MustNewBatchStamp(batches[0].ID)) 173 chunks = append(chunks, ch) 174 err := putter.Put(ctx, ch) 175 if err != nil { 176 t.Fatal(err) 177 } 178 } 179 180 for _, ch := range chunks { 181 stampHash, err := ch.Stamp().Hash() 182 if err != nil { 183 t.Fatal(err) 184 } 185 has, err := st.ReserveHas(ch.Address(), ch.Stamp().BatchID(), stampHash) 186 if err != nil { 187 t.Fatal(err) 188 } 189 190 if !has { 191 t.Fatal("store should have chunk") 192 } 193 194 checkSaved(t, st, ch, true, true) 195 } 196 197 if err := st.Close(); err != nil { 198 t.Fatal(err) 199 } 200 }