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

import (
4
	"context"
5 6
	"testing"

7 8
	"github.com/ipfs/go-ipfs/blocks"

Jeromy's avatar
Jeromy committed
9 10 11
	ds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore"
	syncds "gx/ipfs/QmRWDav6mzWseLWeYfVd5fvUKiVe9xNH29YfMF438fG364/go-datastore/sync"
	cid "gx/ipfs/QmcTcsTvfaeEBRFo1TkFgT8sRmgi1n1LTZpecfVP8fzpGD/go-cid"
12 13
)

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

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

31
func createStores(t *testing.T) (*arccache, *blockstore, *callbackDatastore) {
32 33
	cd := &callbackDatastore{f: func() {}, ds: ds.NewMapDatastore()}
	bs := NewBlockstore(syncds.MutexWrap(cd))
34
	arc, err := testArcCached(bs, nil)
35 36 37
	if err != nil {
		t.Fatal(err)
	}
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
	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)
54 55 56 57 58 59 60 61 62

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

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

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

func TestElideDuplicateWrite(t *testing.T) {
71 72 73 74 75 76 77 78 79 80
	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)

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

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

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

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

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

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

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

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

	untrap(cd)

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

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

121
	if has, err := arc.Has(exampleBlock.Cid()); !has || err != nil {
122 123 124 125
		t.Fatal("has returned invalid result")
	}
}

126
func TestGetAndDeleteFalseShortCircuit(t *testing.T) {
127 128
	arc, _, cd := createStores(t)

129
	arc.Has(exampleBlock.Cid())
130 131 132

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

133
	if bl, err := arc.Get(exampleBlock.Cid()); bl != nil || err != ErrNotFound {
134 135 136
		t.Fatal("get returned invalid result")
	}

137
	if arc.DeleteBlock(exampleBlock.Cid()) != ErrNotFound {
138 139 140 141 142
		t.Fatal("expected ErrNotFound error")
	}
}

func TestArcCreationFailure(t *testing.T) {
143
	if arc, err := newARCCachedBS(context.TODO(), nil, -1); arc != nil || err == nil {
144 145 146 147 148 149 150
		t.Fatal("expected error and no cache")
	}
}

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

151
	bl, err := arc.Get(nil)
152 153 154 155 156 157 158 159 160 161 162 163 164 165

	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)

166
	arc.Get(exampleBlock.Cid())
167 168

	trap("has hit datastore", cd, t)
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	arc.Has(exampleBlock.Cid())
}

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)
188 189 190 191 192 193 194
}

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

	trap("has hit datastore", cd, t)
195
	arc.Has(exampleBlock.Cid())
196
	untrap(cd)
197
	arc.DeleteBlock(exampleBlock.Cid())
198 199 200 201

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