Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(68)

Unified Diff: store.go

Issue 1409173004: Remove usage of unsafe from gkvlite (Closed) Base URL: https://chromium.googlesource.com/external/github.com/luci/gkvlite.git@master
Patch Set: get locks out of other lock Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « node.go ('k') | store_test.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: store.go
diff --git a/store.go b/store.go
index 8e8d6dba66ccc852b8be329229114dc065edb421..e1d7a0bd22c57395cb5decdff66d37f0620dbc83 100644
--- a/store.go
+++ b/store.go
@@ -15,18 +15,41 @@ import (
"sort"
"sync"
"sync/atomic"
- "unsafe"
)
// A persistable store holding collections of ordered keys & values.
type Store struct {
+ m sync.Mutex
+
// Atomic CAS'ed int64/uint64's must be at the top for 32-bit compatibility.
- size int64 // Atomic protected; file size or next write position.
- nodeAllocs uint64 // Atomic protected; total node allocation stats.
- coll unsafe.Pointer // Copy-on-write map[string]*Collection.
- file StoreFile // When nil, we're memory-only or no persistence.
- callbacks StoreCallbacks // Optional / may be nil.
- readOnly bool // When true, Flush()'ing is disallowed.
+ size int64 // Atomic protected; file size or next write position.
+ nodeAllocs uint64 // Atomic protected; total node allocation stats.
+ coll *map[string]*Collection // Copy-on-write map[string]*Collection.
+ file StoreFile // When nil, we're memory-only or no persistence.
+ callbacks StoreCallbacks // Optional / may be nil.
+ readOnly bool // When true, Flush()'ing is disallowed.
+}
+
+func (s *Store) setColl(n *map[string]*Collection) {
+ s.m.Lock()
+ defer s.m.Unlock()
+ s.coll = n
+}
+
+func (s *Store) getColl() *map[string]*Collection {
+ s.m.Lock()
+ defer s.m.Unlock()
+ return s.coll
+}
+
+func (s *Store) casColl(o, n *map[string]*Collection) bool {
+ s.m.Lock()
+ defer s.m.Unlock()
+ if s.coll == o {
+ s.coll = n
+ return true
+ }
+ return false
}
// The StoreFile interface is implemented by os.File. Application
@@ -95,7 +118,7 @@ func NewStore(file StoreFile) (*Store, error) {
func NewStoreEx(file StoreFile,
callbacks StoreCallbacks) (*Store, error) {
coll := make(map[string]*Collection)
- res := &Store{coll: unsafe.Pointer(&coll), callbacks: callbacks}
+ res := &Store{coll: &coll, callbacks: callbacks}
if file == nil || !reflect.ValueOf(file).Elem().IsValid() {
return res, nil // Memory-only Store.
}
@@ -115,7 +138,7 @@ func (s *Store) SetCollection(name string, compare KeyCompare) *Collection {
compare = bytes.Compare
}
for {
- orig := atomic.LoadPointer(&s.coll)
+ orig := s.getColl()
coll := copyColl(*(*map[string]*Collection)(orig))
cnew := s.MakePrivateCollection(compare)
cnew.name = name
@@ -125,7 +148,7 @@ func (s *Store) SetCollection(name string, compare KeyCompare) *Collection {
cnew.root = cold.rootAddRef()
}
coll[name] = cnew
- if atomic.CompareAndSwapPointer(&s.coll, orig, unsafe.Pointer(&coll)) {
+ if s.casColl(orig, &coll) {
cold.closeCollection()
return cnew
}
@@ -149,12 +172,11 @@ func (s *Store) MakePrivateCollection(compare KeyCompare) *Collection {
// Retrieves a named Collection.
func (s *Store) GetCollection(name string) *Collection {
- coll := *(*map[string]*Collection)(atomic.LoadPointer(&s.coll))
- return coll[name]
+ return (*s.getColl())[name]
}
func (s *Store) GetCollectionNames() []string {
- return collNames(*(*map[string]*Collection)(atomic.LoadPointer(&s.coll)))
+ return collNames(*s.getColl())
}
func collNames(coll map[string]*Collection) []string {
@@ -171,11 +193,11 @@ func collNames(coll map[string]*Collection) []string {
// SetCollection(x) is a fast way to empty a Collection.
func (s *Store) RemoveCollection(name string) {
for {
- orig := atomic.LoadPointer(&s.coll)
+ orig := s.getColl()
coll := copyColl(*(*map[string]*Collection)(orig))
cold := coll[name]
delete(coll, name)
- if atomic.CompareAndSwapPointer(&s.coll, orig, unsafe.Pointer(&coll)) {
+ if s.casColl(orig, &coll) {
cold.closeCollection()
return
}
@@ -203,7 +225,7 @@ func (s *Store) Flush() error {
if s.file == nil {
return errors.New("no file / in-memory only, so cannot Flush()")
}
- coll := *(*map[string]*Collection)(atomic.LoadPointer(&s.coll))
+ coll := *s.getColl()
rnls := map[string]*rootNodeLoc{}
cnames := collNames(coll)
for _, name := range cnames {
@@ -231,9 +253,9 @@ func (s *Store) FlushRevert() error {
if s.file == nil {
return errors.New("no file / in-memory only, so cannot FlushRevert()")
}
- orig := atomic.LoadPointer(&s.coll)
+ orig := s.getColl()
coll := make(map[string]*Collection)
- if atomic.CompareAndSwapPointer(&s.coll, orig, unsafe.Pointer(&coll)) {
+ if s.casColl(orig, &coll) {
for _, cold := range *(*map[string]*Collection)(orig) {
cold.closeCollection()
}
@@ -256,9 +278,9 @@ func (s *Store) FlushRevert() error {
// snapshot has its mutations and Flush() operations disabled because
// the original store "owns" writes to the StoreFile.
func (s *Store) Snapshot() (snapshot *Store) {
- coll := copyColl(*(*map[string]*Collection)(atomic.LoadPointer(&s.coll)))
+ coll := copyColl(*s.getColl())
res := &Store{
- coll: unsafe.Pointer(&coll),
+ coll: &coll,
file: s.file,
size: atomic.LoadInt64(&s.size),
readOnly: true,
@@ -278,9 +300,8 @@ func (s *Store) Snapshot() (snapshot *Store) {
func (s *Store) Close() {
s.file = nil
- cptr := atomic.LoadPointer(&s.coll)
- if cptr == nil ||
- !atomic.CompareAndSwapPointer(&s.coll, cptr, unsafe.Pointer(nil)) {
+ cptr := s.getColl()
+ if cptr == nil || !s.casColl(cptr, nil) {
return
}
coll := *(*map[string]*Collection)(cptr)
@@ -299,7 +320,7 @@ func (s *Store) CopyTo(dstFile StoreFile, flushEvery int) (res *Store, err error
if err != nil {
return nil, err
}
- coll := *(*map[string]*Collection)(atomic.LoadPointer(&s.coll))
+ coll := *s.getColl()
for _, name := range collNames(coll) {
srcColl := coll[name]
dstColl := dstStore.SetCollection(name, srcColl.compare)
@@ -452,7 +473,7 @@ func (o *Store) readRootsScan(defaultToEmpty bool) (err error) {
t.compare = bytes.Compare
}
}
- atomic.StorePointer(&o.coll, unsafe.Pointer(&m))
+ o.setColl(&m)
return nil
} // else, perhaps value was unlucky in having MAGIC_END's.
} // else, perhaps a gkvlite file was stored as a value.
« no previous file with comments | « node.go ('k') | store_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698