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  }