@cryptotaxi247 / kubo / commits / d5ce5da5f

Remove fsrepo Datastore refcounting

repo.Once now does refcounts on a whole Repo level, returning the same pointer to multiple Openers. This removes the need for the weird model of separate FSRepo instances pointing to the same underlying storage, and the races caused by that.

Tommi Virtanen committed Mar 13, 2015 at 14:59 UTC d5ce5da5febd3cd2269f1203ed7783c3b3f83441
1 file changed +6 -50
repo/fsrepo/fsrepo.go
+6 -50
@@ -46,11 +46,6 @@ var (
46 // change the repo's state, the package lock does not need to be acquired.
47 openersCounter *counter.Openers
48
49 - // protects dsOpenersCounter and datastores
50 - dsLock sync.Mutex
51 - dsOpenersCounter *counter.Openers
52 - datastores map[string]ds2.ThreadSafeDatastoreCloser
53 -
49 // onlyOne keeps track of open FSRepo instances.
50 //
51 // TODO: once command Context / Repo integration is cleaned up,
@@ -69,9 +64,6 @@ var (
64 func init() {
65 openersCounter = counter.NewOpenersCounter()
66 lockfiles = make(map[string]io.Closer)
72 -
73 - dsOpenersCounter = counter.NewOpenersCounter()
74 - datastores = make(map[string]ds2.ThreadSafeDatastoreCloser)
67 }
68
69 // FSRepo represents an IPFS FileSystem Repo. It is safe for use by multiple
@@ -254,32 +246,14 @@ func (r *FSRepo) openConfig() error {
246
247 // openDatastore returns an error if the config file is not present.
248 func (r *FSRepo) openDatastore() error {
257 - dsLock.Lock()
258 - defer dsLock.Unlock()
259 -
249 dsPath := path.Join(r.path, defaultDataStoreDirectory)
261 -
262 - // if no other goroutines have the datastore Open, initialize it and assign
263 - // it to the package-scoped map for the goroutines that follow.
264 - if dsOpenersCounter.NumOpeners(dsPath) == 0 {
265 - ds, err := levelds.NewDatastore(dsPath, &levelds.Options{
266 - Compression: ldbopts.NoCompression,
267 - })
268 - if err != nil {
269 - return debugerror.New("unable to open leveldb datastore")
270 - }
271 - datastores[dsPath] = ds
272 - }
273 -
274 - // get the datastore from the package-scoped map and record self as an
275 - // opener.
276 - ds, dsIsPresent := datastores[dsPath]
277 - if !dsIsPresent {
278 - // This indicates a programmer error has occurred.
279 - return errors.New("datastore should be available, but it isn't")
250 + ds, err := levelds.NewDatastore(dsPath, &levelds.Options{
251 + Compression: ldbopts.NoCompression,
252 + })
253 + if err != nil {
254 + return debugerror.New("unable to open leveldb datastore")
255 }
256 r.ds = ds
282 - dsOpenersCounter.AddOpener(dsPath) // only after success
257 return nil
258 }
259
@@ -295,24 +269,6 @@ func configureEventLoggerAtRepoPath(c *config.Config, repoPath string) {
269 eventlog.Configure(eventlog.OutputRotatingLogFile(rotateConf))
270 }
271
298 -func (r *FSRepo) closeDatastore() error {
299 - dsLock.Lock()
300 - defer dsLock.Unlock()
301 -
302 - dsPath := path.Join(r.path, defaultDataStoreDirectory)
303 -
304 - // decrement the Opener count. if this goroutine is the last, also close
305 - // the underlying datastore (and remove its reference from the map)
306 -
307 - dsOpenersCounter.RemoveOpener(dsPath)
308 -
309 - if dsOpenersCounter.NumOpeners(dsPath) == 0 {
310 - delete(datastores, dsPath) // remove the reference
311 - return r.ds.Close()
312 - }
313 - return nil
314 -}
315 -
272 // Close closes the FSRepo, releasing held resources.
273 func (r *FSRepo) Close() error {
274 packageLock.Lock()
@@ -322,7 +278,7 @@ func (r *FSRepo) Close() error {
278 return debugerror.Errorf("repo is %s", r.state)
279 }
280
325 - if err := r.closeDatastore(); err != nil {
281 + if err := r.ds.Close(); err != nil {
282 return err
283 }
284