From 1272f90eaed080537f7904282d383f54b91c536b Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Mon, 13 Jun 2016 23:53:05 -0700 Subject: [PATCH] Sequence non-persistent objects in cache Since the datastore interface is common for persistent and non-persistent objects we need to provide the same kind of sequencing and atomicity guarantess to non-persistent data operations as we do for persistent operations. So added sequencing and atomicity checks in the data cache layer. Signed-off-by: Jana Radhakrishnan --- libnetwork/datastore/cache.go | 31 +++++++++++++++++++++++++++++-- libnetwork/datastore/datastore.go | 20 +++++++++++++++----- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/libnetwork/datastore/cache.go b/libnetwork/datastore/cache.go index 2d00038290..97b6009113 100644 --- a/libnetwork/datastore/cache.go +++ b/libnetwork/datastore/cache.go @@ -86,25 +86,52 @@ out: return kmap, nil } -func (c *cache) add(kvObject KVObject) error { +func (c *cache) add(kvObject KVObject, atomic bool) error { kmap, err := c.kmap(kvObject) if err != nil { return err } c.Lock() + // If atomic is true, cache needs to maintain its own index + // for atomicity and the add needs to be atomic. + if atomic { + if prev, ok := kmap[Key(kvObject.Key()...)]; ok { + if prev.Index() != kvObject.Index() { + c.Unlock() + return ErrKeyModified + } + } + + // Increment index + index := kvObject.Index() + index++ + kvObject.SetIndex(index) + } + kmap[Key(kvObject.Key()...)] = kvObject c.Unlock() return nil } -func (c *cache) del(kvObject KVObject) error { +func (c *cache) del(kvObject KVObject, atomic bool) error { kmap, err := c.kmap(kvObject) if err != nil { return err } c.Lock() + // If atomic is true, cache needs to maintain its own index + // for atomicity and del needs to be atomic. + if atomic { + if prev, ok := kmap[Key(kvObject.Key()...)]; ok { + if prev.Index() != kvObject.Index() { + c.Unlock() + return ErrKeyModified + } + } + } + delete(kmap, Key(kvObject.Key()...)) c.Unlock() return nil diff --git a/libnetwork/datastore/datastore.go b/libnetwork/datastore/datastore.go index 49affc7883..63ff717d26 100644 --- a/libnetwork/datastore/datastore.go +++ b/libnetwork/datastore/datastore.go @@ -410,7 +410,9 @@ func (ds *datastore) PutObjectAtomic(kvObject KVObject) error { add_cache: if ds.cache != nil { - return ds.cache.add(kvObject) + // If persistent store is skipped, sequencing needs to + // happen in cache. + return ds.cache.add(kvObject, kvObject.Skip()) } return nil @@ -435,7 +437,9 @@ func (ds *datastore) PutObject(kvObject KVObject) error { add_cache: if ds.cache != nil { - return ds.cache.add(kvObject) + // If persistent store is skipped, sequencing needs to + // happen in cache. + return ds.cache.add(kvObject, kvObject.Skip()) } return nil @@ -537,7 +541,9 @@ func (ds *datastore) DeleteObject(kvObject KVObject) error { // cleaup the cache first if ds.cache != nil { - ds.cache.del(kvObject) + // If persistent store is skipped, sequencing needs to + // happen in cache. + ds.cache.del(kvObject, kvObject.Skip()) } if kvObject.Skip() { @@ -572,7 +578,9 @@ func (ds *datastore) DeleteObjectAtomic(kvObject KVObject) error { del_cache: // cleanup the cache only if AtomicDelete went through successfully if ds.cache != nil { - return ds.cache.del(kvObject) + // If persistent store is skipped, sequencing needs to + // happen in cache. + return ds.cache.del(kvObject, kvObject.Skip()) } return nil @@ -585,7 +593,9 @@ func (ds *datastore) DeleteTree(kvObject KVObject) error { // cleaup the cache first if ds.cache != nil { - ds.cache.del(kvObject) + // If persistent store is skipped, sequencing needs to + // happen in cache. + ds.cache.del(kvObject, kvObject.Skip()) } if kvObject.Skip() {