diff --git a/dataRetriever/resolvers/baseFullHistoryResolver.go b/dataRetriever/resolvers/baseFullHistoryResolver.go index 93bb1e92ff2..0372777f646 100644 --- a/dataRetriever/resolvers/baseFullHistoryResolver.go +++ b/dataRetriever/resolvers/baseFullHistoryResolver.go @@ -10,7 +10,13 @@ type baseFullHistoryResolver struct { func (bfhr *baseFullHistoryResolver) getFromStorage(key []byte, epoch uint32) ([]byte, error) { //we just call the storer to search in the provided epoch. (it will search automatically also in the next epoch) - return bfhr.storer.GetFromEpoch(key, epoch) + buff, err := bfhr.storer.GetFromEpoch(key, epoch) + if err != nil { + // default to a search first, maximize the chance of getting recent data + return bfhr.storer.SearchFirst(key) + } + + return buff, err } func (bfhr *baseFullHistoryResolver) searchFirst(key []byte) ([]byte, error) { diff --git a/dataRetriever/resolvers/baseFullHistoryResolver_test.go b/dataRetriever/resolvers/baseFullHistoryResolver_test.go new file mode 100644 index 00000000000..881820bdd27 --- /dev/null +++ b/dataRetriever/resolvers/baseFullHistoryResolver_test.go @@ -0,0 +1,101 @@ +package resolvers + +import ( + "errors" + "testing" + + "github.com/multiversx/mx-chain-go/testscommon/storage" + "github.com/stretchr/testify/assert" +) + +func TestBaseFullHistoryResolver_SearchFirst(t *testing.T) { + t.Parallel() + + testKey := []byte("key") + testValue := []byte("value") + resolver := &baseFullHistoryResolver{ + storer: &storage.StorerStub{ + SearchFirstCalled: func(key []byte) ([]byte, error) { + assert.Equal(t, testKey, key) + + return testValue, nil + }, + }, + } + + val, err := resolver.searchFirst(testKey) + assert.Nil(t, err) + assert.Equal(t, testValue, val) +} + +func TestBaseFullHistoryResolver_GetFromStorage(t *testing.T) { + t.Parallel() + + testKey := []byte("key") + testValue := []byte("value") + testEpoch := uint32(37) + + t.Run("get from epoch returned nil error and not empty buffer", func(t *testing.T) { + resolver := &baseFullHistoryResolver{ + storer: &storage.StorerStub{ + SearchFirstCalled: func(key []byte) ([]byte, error) { + assert.Fail(t, "should have not called SearchFirst") + + return nil, nil + }, + GetFromEpochCalled: func(key []byte, epoch uint32) ([]byte, error) { + assert.Equal(t, testKey, key) + assert.Equal(t, testEpoch, epoch) + + return testValue, nil + }, + }, + } + + val, err := resolver.getFromStorage(testKey, testEpoch) + assert.Nil(t, err) + assert.Equal(t, testValue, val) + }) + t.Run("get from epoch returned nil error and nil buffer", func(t *testing.T) { + resolver := &baseFullHistoryResolver{ + storer: &storage.StorerStub{ + SearchFirstCalled: func(key []byte) ([]byte, error) { + assert.Fail(t, "should have not called SearchFirst") + + return nil, nil + }, + GetFromEpochCalled: func(key []byte, epoch uint32) ([]byte, error) { + assert.Equal(t, testKey, key) + assert.Equal(t, testEpoch, epoch) + + return nil, nil + }, + }, + } + + val, err := resolver.getFromStorage(testKey, testEpoch) + assert.Nil(t, err) + assert.Equal(t, 0, len(val)) + }) + t.Run("get from epoch returned error will fallback to search first", func(t *testing.T) { + resolver := &baseFullHistoryResolver{ + storer: &storage.StorerStub{ + SearchFirstCalled: func(key []byte) ([]byte, error) { + assert.Equal(t, testKey, key) + + return testValue, nil + }, + GetFromEpochCalled: func(key []byte, epoch uint32) ([]byte, error) { + assert.Equal(t, testKey, key) + assert.Equal(t, testEpoch, epoch) + + return nil, errors.New("not found") + }, + }, + } + + val, err := resolver.getFromStorage(testKey, testEpoch) + assert.Nil(t, err) + assert.Equal(t, testValue, val) + }) +}