diff --git a/go/spec/dataspec.go b/go/spec/dataspec.go index 470808d7cd..053f471db0 100644 --- a/go/spec/dataspec.go +++ b/go/spec/dataspec.go @@ -20,6 +20,7 @@ import ( var ( datasetRe = regexp.MustCompile("^" + dataset.DatasetRe.String() + "$") + ldbStores = map[string]*refCountingLdbStore{} ) func GetDatabase(str string) (datas.Database, error) { @@ -38,7 +39,7 @@ func GetChunkStore(str string) (chunks.ChunkStore, error) { switch sp.Protocol { case "ldb": - return chunks.NewLevelDBStoreUseFlags(sp.Path, ""), nil + return getLDBStore(sp.Path), nil case "mem": return chunks.NewMemoryStore(), nil default: @@ -173,7 +174,7 @@ func (spec databaseSpec) Database() (ds datas.Database, err error) { })) case "ldb": err = d.Unwrap(d.Try(func() { - ds = datas.NewDatabase(chunks.NewLevelDBStoreUseFlags(spec.Path, "")) + ds = datas.NewDatabase(getLDBStore(spec.Path)) })) case "mem": ds = datas.NewDatabase(chunks.NewMemoryStore()) @@ -225,7 +226,6 @@ func RegisterDatabaseFlags(flags *flag.FlagSet) { chunks.RegisterLevelDBFlags(flags) } -// Utility functions to create specs func CreateDatabaseSpecString(protocol, path string) string { return fmt.Sprintf("%s:%s", protocol, path) } @@ -233,3 +233,16 @@ func CreateDatabaseSpecString(protocol, path string) string { func CreateValueSpecString(protocol, path, value string) string { return fmt.Sprintf("%s:%s::%s", protocol, path, value) } + +func getLDBStore(path string) chunks.ChunkStore { + if store, ok := ldbStores[path]; ok { + store.AddRef() + return store + } + + store := newRefCountingLdbStore(path, func() { + delete(ldbStores, path) + }) + ldbStores[path] = store + return store +} diff --git a/go/spec/ref_counting_ldb_store.go b/go/spec/ref_counting_ldb_store.go new file mode 100644 index 0000000000..fa24a90762 --- /dev/null +++ b/go/spec/ref_counting_ldb_store.go @@ -0,0 +1,34 @@ +// Copyright 2016 The Noms Authors. All rights reserved. +// Licensed under the Apache License, version 2.0: +// http://www.apache.org/licenses/LICENSE-2.0 + +package spec + +import ( + "github.com/attic-labs/noms/go/chunks" + "github.com/attic-labs/noms/go/d" +) + +type refCountingLdbStore struct { + *chunks.LevelDBStore + refCount int + closeFn func() +} + +func newRefCountingLdbStore(path string, closeFn func()) *refCountingLdbStore { + return &refCountingLdbStore{chunks.NewLevelDBStoreUseFlags(path, ""), 1, closeFn} +} + +func (r *refCountingLdbStore) AddRef() { + r.refCount++ +} + +func (r *refCountingLdbStore) Close() (err error) { + d.Chk.True(r.refCount > 0) + r.refCount-- + if r.refCount == 0 { + err = r.LevelDBStore.Close() + r.closeFn() + } + return +}