Add caching layer to demo-server (#2228)

This patch creates a new kind of chunks.Factory that demo-server
uses to vend ChunkStore instances that all share the same
MemoryStore-based Chunk cache. This cache _will_ grow without bound,
but the current RAM/data ratio on demo.noms.io means that, in practice,
we will be fine for a bit.

This will need to be removed in favor of a real solution in Issue #2227

Fixes #2009
This commit is contained in:
cmasone-attic
2016-08-01 11:55:16 -07:00
committed by GitHub
parent 1c1d1920bf
commit 55025ee801
4 changed files with 82 additions and 27 deletions
+8 -10
View File
@@ -16,18 +16,16 @@ import (
type MemoryStore struct {
data map[hash.Hash]Chunk
memoryRootTracker
mu *sync.Mutex
mu sync.RWMutex
}
func NewMemoryStore() *MemoryStore {
return &MemoryStore{
mu: &sync.Mutex{},
}
return &MemoryStore{}
}
func (ms *MemoryStore) Get(h hash.Hash) Chunk {
ms.mu.Lock()
defer ms.mu.Unlock()
ms.mu.RLock()
defer ms.mu.RUnlock()
if c, ok := ms.data[h]; ok {
return c
}
@@ -35,8 +33,8 @@ func (ms *MemoryStore) Get(h hash.Hash) Chunk {
}
func (ms *MemoryStore) Has(r hash.Hash) bool {
ms.mu.Lock()
defer ms.mu.Unlock()
ms.mu.RLock()
defer ms.mu.RUnlock()
if ms.data == nil {
return false
}
@@ -65,8 +63,8 @@ func (ms *MemoryStore) PutMany(chunks []Chunk) (e BackpressureError) {
}
func (ms *MemoryStore) Len() int {
ms.mu.Lock()
defer ms.mu.Unlock()
ms.mu.RLock()
defer ms.mu.RUnlock()
return len(ms.data)
}
+12 -17
View File
@@ -5,8 +5,6 @@
package chunks
import (
"sync"
"github.com/attic-labs/noms/go/hash"
"github.com/attic-labs/testify/assert"
)
@@ -30,11 +28,7 @@ type TestStore struct {
}
func NewTestStore() *TestStore {
return &TestStore{
MemoryStore: MemoryStore{
mu: &sync.Mutex{},
},
}
return &TestStore{}
}
func (s *TestStore) Get(h hash.Hash) Chunk {
@@ -59,22 +53,23 @@ func (s *TestStore) PutMany(chunks []Chunk) (e BackpressureError) {
return
}
type testStoreFactory struct {
stores map[string]*TestStore
// TestStoreFactory is public, and exposes Stores to ensure that test code can directly query instances vended by this factory.
type TestStoreFactory struct {
Stores map[string]*TestStore
}
func NewTestStoreFactory() *testStoreFactory {
return &testStoreFactory{map[string]*TestStore{}}
func NewTestStoreFactory() *TestStoreFactory {
return &TestStoreFactory{map[string]*TestStore{}}
}
func (f *testStoreFactory) CreateStore(ns string) ChunkStore {
if cs, present := f.stores[ns]; present {
func (f *TestStoreFactory) CreateStore(ns string) ChunkStore {
if cs, present := f.Stores[ns]; present {
return cs
}
f.stores[ns] = NewTestStore()
return f.stores[ns]
f.Stores[ns] = NewTestStore()
return f.Stores[ns]
}
func (f *testStoreFactory) Shutter() {
f.stores = map[string]*TestStore{}
func (f *TestStoreFactory) Shutter() {
f.Stores = map[string]*TestStore{}
}
@@ -0,0 +1,44 @@
// Copyright 2016 Attic Labs, Inc. All rights reserved.
// Licensed under the Apache License, version 2.0:
// http://www.apache.org/licenses/LICENSE-2.0
package main
import (
"testing"
"github.com/attic-labs/noms/go/chunks"
"github.com/attic-labs/testify/assert"
)
func TestCaching(t *testing.T) {
assert := assert.New(t)
tFactory := chunks.NewTestStoreFactory()
factory := &cachingReadThroughStoreFactory{chunks.NewMemoryStore(), tFactory}
defer factory.Shutter()
chunk := chunks.NewChunk([]byte("abc"))
store1 := factory.CreateStore("ns")
tStore := tFactory.Stores["ns"]
store1.Put(chunk)
assert.Equal(1, tStore.Writes)
assert.Equal(0, tStore.Hases)
assert.True(store1.Has(chunk.Hash()))
assert.Equal(0, tStore.Hases)
assert.Equal(chunk, store1.Get(chunk.Hash()))
assert.Equal(0, tStore.Reads)
assert.True(store1.Has(chunk.Hash()))
assert.Equal(0, tStore.Hases)
// And cache should work across all stores vended by the factory.
store2 := factory.CreateStore("ns")
assert.Equal(chunk, store2.Get(chunk.Hash()))
assert.Equal(0, tStore.Reads)
assert.True(store2.Has(chunk.Hash()))
assert.Equal(0, tStore.Hases)
}
+18
View File
@@ -8,6 +8,7 @@ import (
"fmt"
"github.com/attic-labs/noms/go/chunks"
"github.com/attic-labs/noms/go/d"
flag "github.com/tsuru/gnuflag"
)
@@ -44,7 +45,24 @@ func main() {
factory = chunks.NewMemoryStoreFactory()
fmt.Printf("Using mem ...\n")
}
factory = &cachingReadThroughStoreFactory{chunks.NewMemoryStore(), factory}
defer factory.Shutter()
startWebServer(factory, *authKeyFlag)
}
type cachingReadThroughStoreFactory struct {
cache *chunks.MemoryStore
factory chunks.Factory
}
func (f *cachingReadThroughStoreFactory) CreateStore(ns string) chunks.ChunkStore {
d.Chk.True(f.factory != nil, "Cannot use cachingReadThroughStoreFactory after Shutter().")
return chunks.NewReadThroughStore(f.cache, f.factory.CreateStore(ns))
}
func (f *cachingReadThroughStoreFactory) Shutter() {
f.factory.Shutter()
f.factory = nil
f.cache.Close()
}