From 7ef38b2e0ff9b882d4ec996a63e3e104dabc7786 Mon Sep 17 00:00:00 2001 From: Alvaro Alda Date: Thu, 22 Nov 2018 11:33:44 +0100 Subject: [PATCH] Replace simple cache with free cache to avoid GC runtimes --- balloon/balloon.go | 2 +- balloon/cache/free.go | 86 ++++++++++++++++++++++++++++++++++++ balloon/cache/free_test.go | 73 ++++++++++++++++++++++++++++++ balloon/cache/simple_test.go | 25 ----------- balloon/cache/test_util.go | 24 ++++++++++ balloon/hyper/tree.go | 4 ++ balloon/hyper/tree_test.go | 5 ++- go.mod | 7 +++ go.sum | 18 ++++++++ 9 files changed, 216 insertions(+), 28 deletions(-) create mode 100644 balloon/cache/free.go create mode 100644 balloon/cache/free_test.go diff --git a/balloon/balloon.go b/balloon/balloon.go index ba337c4de..43b84783b 100644 --- a/balloon/balloon.go +++ b/balloon/balloon.go @@ -47,7 +47,7 @@ type Balloon struct { func NewBalloon(store storage.Store, hasherF func() hashing.Hasher) (*Balloon, error) { // create caches - hyperCache := cache.NewSimpleCache(1 << 2) + hyperCache := cache.NewFreeCache(hyper.CacheSize) // create trees historyTree := history.NewHistoryTree(hasherF, store, 30) diff --git a/balloon/cache/free.go b/balloon/cache/free.go new file mode 100644 index 000000000..d6c4b61a5 --- /dev/null +++ b/balloon/cache/free.go @@ -0,0 +1,86 @@ +/* + Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package cache + +import ( + "bytes" + "runtime/debug" + + "github.com/bbva/qed/balloon/navigator" + "github.com/bbva/qed/hashing" + "github.com/bbva/qed/storage" + "github.com/coocood/freecache" +) + +type FreeCache struct { + cached *freecache.Cache +} + +func NewFreeCache(initialSize int) *FreeCache { + cache := freecache.NewCache(initialSize) + debug.SetGCPercent(20) + return &FreeCache{cached: cache} +} + +func (c FreeCache) Get(pos navigator.Position) (hashing.Digest, bool) { + value, err := c.cached.Get(pos.Bytes()) + if err != nil { + return nil, false + } + return value, true +} + +func (c *FreeCache) Put(pos navigator.Position, value hashing.Digest) { + c.cached.Set(pos.Bytes(), value, 0) +} + +func (c *FreeCache) Fill(r storage.KVPairReader) (err error) { + defer r.Close() + for { + entries := make([]*storage.KVPair, 100) + n, err := r.Read(entries) + if err != nil || n == 0 { + break + } + for _, entry := range entries { + if entry != nil { + c.cached.Set(entry.Key, entry.Value, 0) + } + } + } + return nil +} + +func (c FreeCache) Size() int { + return int(c.cached.EntryCount()) +} + +func (c FreeCache) Equal(o *FreeCache) bool { + it := c.cached.NewIterator() + entry := it.Next() + for entry != nil { + v2, err := o.cached.Get(entry.Key) + if err != nil { + return false + } + if !bytes.Equal(entry.Value, v2) { + return false + } + entry = it.Next() + } + return true +} diff --git a/balloon/cache/free_test.go b/balloon/cache/free_test.go new file mode 100644 index 000000000..9cc8ed0fa --- /dev/null +++ b/balloon/cache/free_test.go @@ -0,0 +1,73 @@ +/* + Copyright 2018 Banco Bilbao Vizcaya Argentaria, S.A. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +package cache + +import ( + "testing" + + "github.com/bbva/qed/balloon/navigator" + "github.com/bbva/qed/hashing" + "github.com/bbva/qed/util" + "github.com/stretchr/testify/require" +) + +func TestFreeCache(t *testing.T) { + + testCases := []struct { + pos navigator.Position + value hashing.Digest + cached bool + }{ + {&navigator.FakePosition{[]byte{0x0}, 0}, hashing.Digest{0x1}, true}, + {&navigator.FakePosition{[]byte{0x1}, 0}, hashing.Digest{0x2}, true}, + {&navigator.FakePosition{[]byte{0x2}, 0}, hashing.Digest{0x3}, false}, + } + + cache := NewFreeCache(100 * 1024) + + for i, c := range testCases { + if c.cached { + cache.Put(c.pos, c.value) + } + + cachedValue, ok := cache.Get(c.pos) + + if c.cached { + require.Truef(t, ok, "The key should exists in cache in test case %d", i) + require.Equalf(t, c.value, cachedValue, "The cached value should be equal to stored value in test case %d", i) + } else { + require.Falsef(t, ok, "The key should not exist in cache in test case %d", i) + } + } +} + +func TestFillFreeCache(t *testing.T) { + + numElems := uint64(10000) + cache := NewFreeCache(10000 * 1024) + reader := NewFakeKVPairReader(numElems) + + err := cache.Fill(reader) + + require.NoError(t, err) + require.Truef(t, reader.Remaining == 0, "All elements should be cached. Remaining: %d", reader.Remaining) + + for i := uint64(0); i < numElems; i++ { + pos := &navigator.FakePosition{util.Uint64AsBytes(i), 0} + _, ok := cache.Get(pos) + require.Truef(t, ok, "The element in position %v should be in cache", pos) + } +} diff --git a/balloon/cache/simple_test.go b/balloon/cache/simple_test.go index 4e89ee8c5..60f4b6635 100644 --- a/balloon/cache/simple_test.go +++ b/balloon/cache/simple_test.go @@ -23,9 +23,6 @@ import ( "github.com/bbva/qed/hashing" "github.com/bbva/qed/util" "github.com/stretchr/testify/require" - - "github.com/bbva/qed/storage" - "github.com/bbva/qed/testutils/rand" ) func TestSimpleCache(t *testing.T) { @@ -75,25 +72,3 @@ func TestFillSimpleCache(t *testing.T) { require.Truef(t, ok, "The element in position %v should be in cache", pos) } } - -type FakeKVPairReader struct { - Remaining uint64 - index uint64 -} - -func NewFakeKVPairReader(numElems uint64) *FakeKVPairReader { - return &FakeKVPairReader{numElems, 0} -} - -func (r *FakeKVPairReader) Read(buffer []*storage.KVPair) (n int, err error) { - for n = 0; r.Remaining > 0 && n < len(buffer); n++ { - pos := &navigator.FakePosition{util.Uint64AsBytes(r.index), 0} - buffer[n] = &storage.KVPair{pos.Bytes(), rand.Bytes(8)} - r.Remaining-- - r.index++ - } - return n, nil -} -func (r *FakeKVPairReader) Close() { - r.Remaining = 0 -} diff --git a/balloon/cache/test_util.go b/balloon/cache/test_util.go index a99bc28ab..7be9c52e8 100644 --- a/balloon/cache/test_util.go +++ b/balloon/cache/test_util.go @@ -20,6 +20,8 @@ import ( "github.com/bbva/qed/balloon/navigator" "github.com/bbva/qed/hashing" "github.com/bbva/qed/storage" + "github.com/bbva/qed/testutils/rand" + "github.com/bbva/qed/util" ) type FakeCache struct { @@ -39,3 +41,25 @@ func (c *FakeCache) Put(pos navigator.Position, value hashing.Digest) {} func (c *FakeCache) Fill(r storage.KVPairReader) error { return nil } func (c FakeCache) Size() int { return 1 } + +type FakeKVPairReader struct { + Remaining uint64 + index uint64 +} + +func NewFakeKVPairReader(numElems uint64) *FakeKVPairReader { + return &FakeKVPairReader{numElems, 0} +} + +func (r *FakeKVPairReader) Read(buffer []*storage.KVPair) (n int, err error) { + for n = 0; r.Remaining > 0 && n < len(buffer); n++ { + pos := &navigator.FakePosition{util.Uint64AsBytes(r.index), 0} + buffer[n] = &storage.KVPair{pos.Bytes(), rand.Bytes(8)} + r.Remaining-- + r.index++ + } + return n, nil +} +func (r *FakeKVPairReader) Close() { + r.Remaining = 0 +} diff --git a/balloon/hyper/tree.go b/balloon/hyper/tree.go index 255d4e98b..053e518a9 100644 --- a/balloon/hyper/tree.go +++ b/balloon/hyper/tree.go @@ -31,6 +31,10 @@ import ( "github.com/bbva/qed/util" ) +const ( + CacheSize int = (1 << 26) * 68 // 2^26 elements * 68 bytes for entry +) + type HyperTree struct { store storage.Store cache cache.ModifiableCache diff --git a/balloon/hyper/tree_test.go b/balloon/hyper/tree_test.go index fb92ac7f5..fc30b68e9 100644 --- a/balloon/hyper/tree_test.go +++ b/balloon/hyper/tree_test.go @@ -289,8 +289,8 @@ func BenchmarkAdd(b *testing.B) { defer closeF() hasher := hashing.NewSha256Hasher() - simpleCache := cache.NewSimpleCache(0) - tree := NewHyperTree(hashing.NewSha256Hasher, store, simpleCache) + freeCache := cache.NewFreeCache(CacheSize) + tree := NewHyperTree(hashing.NewSha256Hasher, store, freeCache) b.ResetTimer() b.N = 100000 @@ -299,4 +299,5 @@ func BenchmarkAdd(b *testing.B) { _, mutations, _ := tree.Add(key, uint64(i)) store.Mutate(mutations) } + } diff --git a/go.mod b/go.mod index c840c4731..2dd8c4dd9 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,24 @@ module github.com/bbva/qed require ( github.com/bbva/raft-badger v0.1.1 github.com/boltdb/bolt v1.3.1 // indirect + github.com/cespare/xxhash v1.1.0 // indirect + github.com/coocood/freecache v1.0.1 github.com/coreos/bbolt v1.3.0 github.com/dgraph-io/badger v1.5.4 github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c + github.com/hashicorp/go-multierror v1.0.0 // indirect + github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 // indirect + github.com/hashicorp/memberlist v0.1.0 github.com/hashicorp/raft v1.0.0 github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/influxdata/tdigest v0.0.0-20180711151920-a7d76c6f093a // indirect github.com/kr/pty v1.1.3 // indirect github.com/lucasb-eyer/go-colorful v0.0.0-20180709185858-c7842319cf3a // indirect github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 // indirect + github.com/miekg/dns v1.0.15 // indirect + github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 // indirect github.com/spf13/cobra v0.0.3 github.com/spf13/pflag v1.0.3 // indirect github.com/streadway/quantile v0.0.0-20150917103942-b0c588724d25 // indirect diff --git a/go.sum b/go.sum index 6e72ae48e..9c27c3a68 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,7 @@ github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57 h1:CVuXDbdzPW github.com/AndreasBriese/bbloom v0.0.0-20170702084017-28f7e881ca57/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7 h1:PqzgE6kAMi81xWQA2QIVxjWkFHptGgC547vchpUbtFo= github.com/AndreasBriese/bbloom v0.0.0-20180913140656-343706a395b7/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/armon/go-metrics v0.0.0-20180713145231-3c58d8115a78 h1:mdRSArcFLfW0VoL34LZAKSz6LkkK4jFxVx2xYavACMg= github.com/armon/go-metrics v0.0.0-20180713145231-3c58d8115a78/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I= @@ -14,6 +15,10 @@ github.com/bbva/raft-badger v0.1.1 h1:v0BlEP2glTd3o1U4ShD4HtyGc08PXt4gcEBdO6Fh7O github.com/bbva/raft-badger v0.1.1/go.mod h1:KqKb1IrW6hsgFSzXTavxddJH+5E3TmDxBbFhitk0vpY= github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/coocood/freecache v1.0.1 h1:oFyo4msX2c0QIKU+kuMJUwsKamJ+AKc2JJrKcMszJ5M= +github.com/coocood/freecache v1.0.1/go.mod h1:ePwxCDzOYvARfHdr1pByNct1at3CoKnsipOHwKlNbzI= github.com/coreos/bbolt v1.3.0 h1:HIgH5xUWXT914HCI671AxuTTqjj64UOFr7pHn48LUTI= github.com/coreos/bbolt v1.3.0/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -30,14 +35,22 @@ github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c h1:964Od4U6p2jUkFxvCydnIczKteheJEzHRToSGK3Bnlw= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= +github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c h1:BTAbnbegUIMB6xmQCwWE8yRzbA4XSpnZY5hvRJC188I= github.com/hashicorp/go-msgpack v0.0.0-20150518234257-fa3f63826f7c/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM= +github.com/hashicorp/go-multierror v1.0.0 h1:iVjPR7a6H0tWELX5NxNe7bYopibicUzc7uPribsnS6o= +github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk= +github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86 h1:7YOlAIO2YWnJZkQp7B5eFykaIY7C9JndqAFQyVV5BhM= +github.com/hashicorp/go-sockaddr v0.0.0-20180320115054-6d291a969b86/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-uuid v1.0.0 h1:RS8zrF7PhGwyNPOtxSClXXj9HA8feRnJzgnI1RJCSnM= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/memberlist v0.1.0 h1:qSsCiC0WYD39lbSitKNt40e30uorm2Ss/d4JGU1hzH8= +github.com/hashicorp/memberlist v0.1.0/go.mod h1:ncdBp14cuox2iFOq3kDiquKU6fqsTBc3W6JvZwjxxsE= github.com/hashicorp/raft v1.0.0 h1:htBVktAOtGs4Le5Z7K8SF5H2+oWsQFYVmOgH5loro7Y= github.com/hashicorp/raft v1.0.0/go.mod h1:DVSAWItjLjTOkVbSpWQ0j0kUADIvDaCtBxIcbNAQLkI= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= @@ -54,12 +67,17 @@ github.com/lucasb-eyer/go-colorful v0.0.0-20180709185858-c7842319cf3a h1:B2QfFRl github.com/lucasb-eyer/go-colorful v0.0.0-20180709185858-c7842319cf3a/go.mod h1:NXg0ArsFk0Y01623LgUqoqcouGDB+PwCCQlrwrG6xJ4= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329 h1:2gxZ0XQIU/5z3Z3bUBu+FXuk2pFbkN6tcwi/pjyaDic= github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/miekg/dns v1.0.15 h1:9+UupePBQCG6zf1q/bGmTO1vumoG13jsrbWOSX1W6Tw= +github.com/miekg/dns v1.0.15/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c h1:Lgl0gzECD8GnQ5QCWA8o6BtfL6mDH5rQgM4/fX3avOs= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529 h1:nn5Wsu0esKSJiIVhscUtVbo7ada43DJhG55ua/hjS5I= +github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/pflag v1.0.2 h1:Fy0orTDgHdbnzHcsOgfCN4LtHf0ec3wwtiwJqwvf3Gc=