arc_cache_test.go 5.25 KB
Newer Older
1 2 3
package blockstore

import (
4
	"context"
5 6
	"testing"

7
	blocks "github.com/ipfs/go-block-format"
8 9 10
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	syncds "github.com/ipfs/go-datastore/sync"
11 12
)

13 14
var exampleBlock = blocks.NewBlock([]byte("foo"))

15
func testArcCached(ctx context.Context, bs Blockstore) (*arccache, error) {
16 17 18 19 20 21
	if ctx == nil {
		ctx = context.TODO()
	}
	opts := DefaultCacheOpts()
	opts.HasBloomFilterSize = 0
	opts.HasBloomFilterHashes = 0
22
	bbs, err := CachedBlockstore(ctx, bs, opts)
23 24 25
	if err == nil {
		return bbs.(*arccache), nil
	}
26
	return nil, err
27 28
}

29
func createStores(t *testing.T) (*arccache, Blockstore, *callbackDatastore) {
30 31
	cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
	bs := NewBlockstore(syncds.MutexWrap(cd))
32
	arc, err := testArcCached(context.TODO(), bs)
33 34 35
	if err != nil {
		t.Fatal(err)
	}
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
	return arc, bs, cd
}

func trap(message string, cd *callbackDatastore, t *testing.T) {
	cd.SetFunc(func() {
		t.Fatal(message)
	})
}
func untrap(cd *callbackDatastore) {
	cd.SetFunc(func() {})
}

func TestRemoveCacheEntryOnDelete(t *testing.T) {
	arc, _, cd := createStores(t)

	arc.Put(exampleBlock)
52 53 54 55 56 57 58 59 60

	cd.Lock()
	writeHitTheDatastore := false
	cd.Unlock()

	cd.SetFunc(func() {
		writeHitTheDatastore = true
	})

61
	arc.DeleteBlock(exampleBlock.Cid())
62
	arc.Put(exampleBlock)
63 64 65 66 67 68
	if !writeHitTheDatastore {
		t.Fail()
	}
}

func TestElideDuplicateWrite(t *testing.T) {
69 70 71 72 73 74 75 76 77 78
	arc, _, cd := createStores(t)

	arc.Put(exampleBlock)
	trap("write hit datastore", cd, t)
	arc.Put(exampleBlock)
}

func TestHasRequestTriggersCache(t *testing.T) {
	arc, _, cd := createStores(t)

79
	arc.Has(exampleBlock.Cid())
80
	trap("has hit datastore", cd, t)
81
	if has, err := arc.Has(exampleBlock.Cid()); has || err != nil {
82 83 84 85 86
		t.Fatal("has was true but there is no such block")
	}

	untrap(cd)
	err := arc.Put(exampleBlock)
87 88 89 90
	if err != nil {
		t.Fatal(err)
	}

91
	trap("has hit datastore", cd, t)
92

93
	if has, err := arc.Has(exampleBlock.Cid()); !has || err != nil {
94 95 96 97 98 99 100
		t.Fatal("has returned invalid result")
	}
}

func TestGetFillsCache(t *testing.T) {
	arc, _, cd := createStores(t)

101
	if bl, err := arc.Get(exampleBlock.Cid()); bl != nil || err == nil {
102 103 104 105 106
		t.Fatal("block was found or there was no error")
	}

	trap("has hit datastore", cd, t)

107
	if has, err := arc.Has(exampleBlock.Cid()); has || err != nil {
108 109
		t.Fatal("has was true but there is no such block")
	}
110 111 112
	if blockSize, err := arc.GetSize(exampleBlock.Cid()); blockSize > -1 || err != nil {
		t.Fatal("getsize was true but there is no such block")
	}
113 114 115 116 117 118 119 120 121

	untrap(cd)

	if err := arc.Put(exampleBlock); err != nil {
		t.Fatal(err)
	}

	trap("has hit datastore", cd, t)

122
	if has, err := arc.Has(exampleBlock.Cid()); !has || err != nil {
123 124
		t.Fatal("has returned invalid result")
	}
125 126 127
	if blockSize, err := arc.GetSize(exampleBlock.Cid()); blockSize == -1 || err != nil {
		t.Fatal("getsize returned invalid result")
	}
128 129
}

130
func TestGetAndDeleteFalseShortCircuit(t *testing.T) {
131 132
	arc, _, cd := createStores(t)

133
	arc.Has(exampleBlock.Cid())
134
	arc.GetSize(exampleBlock.Cid())
135 136 137

	trap("get hit datastore", cd, t)

138
	if bl, err := arc.Get(exampleBlock.Cid()); bl != nil || err != ErrNotFound {
139 140 141
		t.Fatal("get returned invalid result")
	}

142
	if arc.DeleteBlock(exampleBlock.Cid()) != ErrNotFound {
143 144 145 146 147
		t.Fatal("expected ErrNotFound error")
	}
}

func TestArcCreationFailure(t *testing.T) {
148
	if arc, err := newARCCachedBS(context.TODO(), nil, -1); arc != nil || err == nil {
149 150 151 152 153 154 155
		t.Fatal("expected error and no cache")
	}
}

func TestInvalidKey(t *testing.T) {
	arc, _, _ := createStores(t)

156
	bl, err := arc.Get(cid.Cid{})
157 158 159 160 161 162 163 164 165 166 167 168 169 170

	if bl != nil {
		t.Fatal("blocks should be nil")
	}
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestHasAfterSucessfulGetIsCached(t *testing.T) {
	arc, bs, cd := createStores(t)

	bs.Put(exampleBlock)

171
	arc.Get(exampleBlock.Cid())
172 173

	trap("has hit datastore", cd, t)
174 175 176
	arc.Has(exampleBlock.Cid())
}

177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
func TestGetSizeAfterSucessfulGetIsCached(t *testing.T) {
	arc, bs, cd := createStores(t)

	bs.Put(exampleBlock)

	arc.Get(exampleBlock.Cid())

	trap("has hit datastore", cd, t)
	arc.GetSize(exampleBlock.Cid())
}

func TestGetSizeMissingZeroSizeBlock(t *testing.T) {
	arc, bs, cd := createStores(t)
	emptyBlock := blocks.NewBlock([]byte{})
	missingBlock := blocks.NewBlock([]byte("missingBlock"))

	bs.Put(emptyBlock)

	arc.Get(emptyBlock.Cid())

	trap("has hit datastore", cd, t)
	if blockSize, err := arc.GetSize(emptyBlock.Cid()); blockSize != 0 || err != nil {
		t.Fatal("getsize returned invalid result")
	}
	untrap(cd)

	arc.Get(missingBlock.Cid())

	trap("has hit datastore", cd, t)
	if blockSize, err := arc.GetSize(missingBlock.Cid()); blockSize != -1 || err != nil {
		t.Fatal("getsize returned invalid result")
	}
}


212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
func TestDifferentKeyObjectsWork(t *testing.T) {
	arc, bs, cd := createStores(t)

	bs.Put(exampleBlock)

	arc.Get(exampleBlock.Cid())

	trap("has hit datastore", cd, t)
	cidstr := exampleBlock.Cid().String()

	ncid, err := cid.Decode(cidstr)
	if err != nil {
		t.Fatal(err)
	}

	arc.Has(ncid)
228 229 230 231 232 233 234
}

func TestPutManyCaches(t *testing.T) {
	arc, _, cd := createStores(t)
	arc.PutMany([]blocks.Block{exampleBlock})

	trap("has hit datastore", cd, t)
235
	arc.Has(exampleBlock.Cid())
236
	arc.GetSize(exampleBlock.Cid())
237
	untrap(cd)
238
	arc.DeleteBlock(exampleBlock.Cid())
239 240 241 242

	arc.Put(exampleBlock)
	trap("PunMany has hit datastore", cd, t)
	arc.PutMany([]blocks.Block{exampleBlock})
243
}