OSDN Git Service

Thanos did someting
[bytom/vapor.git] / vendor / github.com / syndtr / goleveldb / leveldb / cache / cache.go
diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go b/vendor/github.com/syndtr/goleveldb/leveldb/cache/cache.go
deleted file mode 100644 (file)
index c5940b2..0000000
+++ /dev/null
@@ -1,705 +0,0 @@
-// Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
-// All rights reserved.
-//
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Package cache provides interface and implementation of a cache algorithms.
-package cache
-
-import (
-       "sync"
-       "sync/atomic"
-       "unsafe"
-
-       "github.com/syndtr/goleveldb/leveldb/util"
-)
-
-// Cacher provides interface to implements a caching functionality.
-// An implementation must be safe for concurrent use.
-type Cacher interface {
-       // Capacity returns cache capacity.
-       Capacity() int
-
-       // SetCapacity sets cache capacity.
-       SetCapacity(capacity int)
-
-       // Promote promotes the 'cache node'.
-       Promote(n *Node)
-
-       // Ban evicts the 'cache node' and prevent subsequent 'promote'.
-       Ban(n *Node)
-
-       // Evict evicts the 'cache node'.
-       Evict(n *Node)
-
-       // EvictNS evicts 'cache node' with the given namespace.
-       EvictNS(ns uint64)
-
-       // EvictAll evicts all 'cache node'.
-       EvictAll()
-
-       // Close closes the 'cache tree'
-       Close() error
-}
-
-// Value is a 'cacheable object'. It may implements util.Releaser, if
-// so the the Release method will be called once object is released.
-type Value interface{}
-
-// NamespaceGetter provides convenient wrapper for namespace.
-type NamespaceGetter struct {
-       Cache *Cache
-       NS    uint64
-}
-
-// Get simply calls Cache.Get() method.
-func (g *NamespaceGetter) Get(key uint64, setFunc func() (size int, value Value)) *Handle {
-       return g.Cache.Get(g.NS, key, setFunc)
-}
-
-// The hash tables implementation is based on:
-// "Dynamic-Sized Nonblocking Hash Tables", by Yujie Liu,
-// Kunlong Zhang, and Michael Spear.
-// ACM Symposium on Principles of Distributed Computing, Jul 2014.
-
-const (
-       mInitialSize           = 1 << 4
-       mOverflowThreshold     = 1 << 5
-       mOverflowGrowThreshold = 1 << 7
-)
-
-type mBucket struct {
-       mu     sync.Mutex
-       node   []*Node
-       frozen bool
-}
-
-func (b *mBucket) freeze() []*Node {
-       b.mu.Lock()
-       defer b.mu.Unlock()
-       if !b.frozen {
-               b.frozen = true
-       }
-       return b.node
-}
-
-func (b *mBucket) get(r *Cache, h *mNode, hash uint32, ns, key uint64, noset bool) (done, added bool, n *Node) {
-       b.mu.Lock()
-
-       if b.frozen {
-               b.mu.Unlock()
-               return
-       }
-
-       // Scan the node.
-       for _, n := range b.node {
-               if n.hash == hash && n.ns == ns && n.key == key {
-                       atomic.AddInt32(&n.ref, 1)
-                       b.mu.Unlock()
-                       return true, false, n
-               }
-       }
-
-       // Get only.
-       if noset {
-               b.mu.Unlock()
-               return true, false, nil
-       }
-
-       // Create node.
-       n = &Node{
-               r:    r,
-               hash: hash,
-               ns:   ns,
-               key:  key,
-               ref:  1,
-       }
-       // Add node to bucket.
-       b.node = append(b.node, n)
-       bLen := len(b.node)
-       b.mu.Unlock()
-
-       // Update counter.
-       grow := atomic.AddInt32(&r.nodes, 1) >= h.growThreshold
-       if bLen > mOverflowThreshold {
-               grow = grow || atomic.AddInt32(&h.overflow, 1) >= mOverflowGrowThreshold
-       }
-
-       // Grow.
-       if grow && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) {
-               nhLen := len(h.buckets) << 1
-               nh := &mNode{
-                       buckets:         make([]unsafe.Pointer, nhLen),
-                       mask:            uint32(nhLen) - 1,
-                       pred:            unsafe.Pointer(h),
-                       growThreshold:   int32(nhLen * mOverflowThreshold),
-                       shrinkThreshold: int32(nhLen >> 1),
-               }
-               ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh))
-               if !ok {
-                       panic("BUG: failed swapping head")
-               }
-               go nh.initBuckets()
-       }
-
-       return true, true, n
-}
-
-func (b *mBucket) delete(r *Cache, h *mNode, hash uint32, ns, key uint64) (done, deleted bool) {
-       b.mu.Lock()
-
-       if b.frozen {
-               b.mu.Unlock()
-               return
-       }
-
-       // Scan the node.
-       var (
-               n    *Node
-               bLen int
-       )
-       for i := range b.node {
-               n = b.node[i]
-               if n.ns == ns && n.key == key {
-                       if atomic.LoadInt32(&n.ref) == 0 {
-                               deleted = true
-
-                               // Call releaser.
-                               if n.value != nil {
-                                       if r, ok := n.value.(util.Releaser); ok {
-                                               r.Release()
-                                       }
-                                       n.value = nil
-                               }
-
-                               // Remove node from bucket.
-                               b.node = append(b.node[:i], b.node[i+1:]...)
-                               bLen = len(b.node)
-                       }
-                       break
-               }
-       }
-       b.mu.Unlock()
-
-       if deleted {
-               // Call OnDel.
-               for _, f := range n.onDel {
-                       f()
-               }
-
-               // Update counter.
-               atomic.AddInt32(&r.size, int32(n.size)*-1)
-               shrink := atomic.AddInt32(&r.nodes, -1) < h.shrinkThreshold
-               if bLen >= mOverflowThreshold {
-                       atomic.AddInt32(&h.overflow, -1)
-               }
-
-               // Shrink.
-               if shrink && len(h.buckets) > mInitialSize && atomic.CompareAndSwapInt32(&h.resizeInProgess, 0, 1) {
-                       nhLen := len(h.buckets) >> 1
-                       nh := &mNode{
-                               buckets:         make([]unsafe.Pointer, nhLen),
-                               mask:            uint32(nhLen) - 1,
-                               pred:            unsafe.Pointer(h),
-                               growThreshold:   int32(nhLen * mOverflowThreshold),
-                               shrinkThreshold: int32(nhLen >> 1),
-                       }
-                       ok := atomic.CompareAndSwapPointer(&r.mHead, unsafe.Pointer(h), unsafe.Pointer(nh))
-                       if !ok {
-                               panic("BUG: failed swapping head")
-                       }
-                       go nh.initBuckets()
-               }
-       }
-
-       return true, deleted
-}
-
-type mNode struct {
-       buckets         []unsafe.Pointer // []*mBucket
-       mask            uint32
-       pred            unsafe.Pointer // *mNode
-       resizeInProgess int32
-
-       overflow        int32
-       growThreshold   int32
-       shrinkThreshold int32
-}
-
-func (n *mNode) initBucket(i uint32) *mBucket {
-       if b := (*mBucket)(atomic.LoadPointer(&n.buckets[i])); b != nil {
-               return b
-       }
-
-       p := (*mNode)(atomic.LoadPointer(&n.pred))
-       if p != nil {
-               var node []*Node
-               if n.mask > p.mask {
-                       // Grow.
-                       pb := (*mBucket)(atomic.LoadPointer(&p.buckets[i&p.mask]))
-                       if pb == nil {
-                               pb = p.initBucket(i & p.mask)
-                       }
-                       m := pb.freeze()
-                       // Split nodes.
-                       for _, x := range m {
-                               if x.hash&n.mask == i {
-                                       node = append(node, x)
-                               }
-                       }
-               } else {
-                       // Shrink.
-                       pb0 := (*mBucket)(atomic.LoadPointer(&p.buckets[i]))
-                       if pb0 == nil {
-                               pb0 = p.initBucket(i)
-                       }
-                       pb1 := (*mBucket)(atomic.LoadPointer(&p.buckets[i+uint32(len(n.buckets))]))
-                       if pb1 == nil {
-                               pb1 = p.initBucket(i + uint32(len(n.buckets)))
-                       }
-                       m0 := pb0.freeze()
-                       m1 := pb1.freeze()
-                       // Merge nodes.
-                       node = make([]*Node, 0, len(m0)+len(m1))
-                       node = append(node, m0...)
-                       node = append(node, m1...)
-               }
-               b := &mBucket{node: node}
-               if atomic.CompareAndSwapPointer(&n.buckets[i], nil, unsafe.Pointer(b)) {
-                       if len(node) > mOverflowThreshold {
-                               atomic.AddInt32(&n.overflow, int32(len(node)-mOverflowThreshold))
-                       }
-                       return b
-               }
-       }
-
-       return (*mBucket)(atomic.LoadPointer(&n.buckets[i]))
-}
-
-func (n *mNode) initBuckets() {
-       for i := range n.buckets {
-               n.initBucket(uint32(i))
-       }
-       atomic.StorePointer(&n.pred, nil)
-}
-
-// Cache is a 'cache map'.
-type Cache struct {
-       mu     sync.RWMutex
-       mHead  unsafe.Pointer // *mNode
-       nodes  int32
-       size   int32
-       cacher Cacher
-       closed bool
-}
-
-// NewCache creates a new 'cache map'. The cacher is optional and
-// may be nil.
-func NewCache(cacher Cacher) *Cache {
-       h := &mNode{
-               buckets:         make([]unsafe.Pointer, mInitialSize),
-               mask:            mInitialSize - 1,
-               growThreshold:   int32(mInitialSize * mOverflowThreshold),
-               shrinkThreshold: 0,
-       }
-       for i := range h.buckets {
-               h.buckets[i] = unsafe.Pointer(&mBucket{})
-       }
-       r := &Cache{
-               mHead:  unsafe.Pointer(h),
-               cacher: cacher,
-       }
-       return r
-}
-
-func (r *Cache) getBucket(hash uint32) (*mNode, *mBucket) {
-       h := (*mNode)(atomic.LoadPointer(&r.mHead))
-       i := hash & h.mask
-       b := (*mBucket)(atomic.LoadPointer(&h.buckets[i]))
-       if b == nil {
-               b = h.initBucket(i)
-       }
-       return h, b
-}
-
-func (r *Cache) delete(n *Node) bool {
-       for {
-               h, b := r.getBucket(n.hash)
-               done, deleted := b.delete(r, h, n.hash, n.ns, n.key)
-               if done {
-                       return deleted
-               }
-       }
-       return false
-}
-
-// Nodes returns number of 'cache node' in the map.
-func (r *Cache) Nodes() int {
-       return int(atomic.LoadInt32(&r.nodes))
-}
-
-// Size returns sums of 'cache node' size in the map.
-func (r *Cache) Size() int {
-       return int(atomic.LoadInt32(&r.size))
-}
-
-// Capacity returns cache capacity.
-func (r *Cache) Capacity() int {
-       if r.cacher == nil {
-               return 0
-       }
-       return r.cacher.Capacity()
-}
-
-// SetCapacity sets cache capacity.
-func (r *Cache) SetCapacity(capacity int) {
-       if r.cacher != nil {
-               r.cacher.SetCapacity(capacity)
-       }
-}
-
-// Get gets 'cache node' with the given namespace and key.
-// If cache node is not found and setFunc is not nil, Get will atomically creates
-// the 'cache node' by calling setFunc. Otherwise Get will returns nil.
-//
-// The returned 'cache handle' should be released after use by calling Release
-// method.
-func (r *Cache) Get(ns, key uint64, setFunc func() (size int, value Value)) *Handle {
-       r.mu.RLock()
-       defer r.mu.RUnlock()
-       if r.closed {
-               return nil
-       }
-
-       hash := murmur32(ns, key, 0xf00)
-       for {
-               h, b := r.getBucket(hash)
-               done, _, n := b.get(r, h, hash, ns, key, setFunc == nil)
-               if done {
-                       if n != nil {
-                               n.mu.Lock()
-                               if n.value == nil {
-                                       if setFunc == nil {
-                                               n.mu.Unlock()
-                                               n.unref()
-                                               return nil
-                                       }
-
-                                       n.size, n.value = setFunc()
-                                       if n.value == nil {
-                                               n.size = 0
-                                               n.mu.Unlock()
-                                               n.unref()
-                                               return nil
-                                       }
-                                       atomic.AddInt32(&r.size, int32(n.size))
-                               }
-                               n.mu.Unlock()
-                               if r.cacher != nil {
-                                       r.cacher.Promote(n)
-                               }
-                               return &Handle{unsafe.Pointer(n)}
-                       }
-
-                       break
-               }
-       }
-       return nil
-}
-
-// Delete removes and ban 'cache node' with the given namespace and key.
-// A banned 'cache node' will never inserted into the 'cache tree'. Ban
-// only attributed to the particular 'cache node', so when a 'cache node'
-// is recreated it will not be banned.
-//
-// If onDel is not nil, then it will be executed if such 'cache node'
-// doesn't exist or once the 'cache node' is released.
-//
-// Delete return true is such 'cache node' exist.
-func (r *Cache) Delete(ns, key uint64, onDel func()) bool {
-       r.mu.RLock()
-       defer r.mu.RUnlock()
-       if r.closed {
-               return false
-       }
-
-       hash := murmur32(ns, key, 0xf00)
-       for {
-               h, b := r.getBucket(hash)
-               done, _, n := b.get(r, h, hash, ns, key, true)
-               if done {
-                       if n != nil {
-                               if onDel != nil {
-                                       n.mu.Lock()
-                                       n.onDel = append(n.onDel, onDel)
-                                       n.mu.Unlock()
-                               }
-                               if r.cacher != nil {
-                                       r.cacher.Ban(n)
-                               }
-                               n.unref()
-                               return true
-                       }
-
-                       break
-               }
-       }
-
-       if onDel != nil {
-               onDel()
-       }
-
-       return false
-}
-
-// Evict evicts 'cache node' with the given namespace and key. This will
-// simply call Cacher.Evict.
-//
-// Evict return true is such 'cache node' exist.
-func (r *Cache) Evict(ns, key uint64) bool {
-       r.mu.RLock()
-       defer r.mu.RUnlock()
-       if r.closed {
-               return false
-       }
-
-       hash := murmur32(ns, key, 0xf00)
-       for {
-               h, b := r.getBucket(hash)
-               done, _, n := b.get(r, h, hash, ns, key, true)
-               if done {
-                       if n != nil {
-                               if r.cacher != nil {
-                                       r.cacher.Evict(n)
-                               }
-                               n.unref()
-                               return true
-                       }
-
-                       break
-               }
-       }
-
-       return false
-}
-
-// EvictNS evicts 'cache node' with the given namespace. This will
-// simply call Cacher.EvictNS.
-func (r *Cache) EvictNS(ns uint64) {
-       r.mu.RLock()
-       defer r.mu.RUnlock()
-       if r.closed {
-               return
-       }
-
-       if r.cacher != nil {
-               r.cacher.EvictNS(ns)
-       }
-}
-
-// EvictAll evicts all 'cache node'. This will simply call Cacher.EvictAll.
-func (r *Cache) EvictAll() {
-       r.mu.RLock()
-       defer r.mu.RUnlock()
-       if r.closed {
-               return
-       }
-
-       if r.cacher != nil {
-               r.cacher.EvictAll()
-       }
-}
-
-// Close closes the 'cache map' and forcefully releases all 'cache node'.
-func (r *Cache) Close() error {
-       r.mu.Lock()
-       if !r.closed {
-               r.closed = true
-
-               h := (*mNode)(r.mHead)
-               h.initBuckets()
-
-               for i := range h.buckets {
-                       b := (*mBucket)(h.buckets[i])
-                       for _, n := range b.node {
-                               // Call releaser.
-                               if n.value != nil {
-                                       if r, ok := n.value.(util.Releaser); ok {
-                                               r.Release()
-                                       }
-                                       n.value = nil
-                               }
-
-                               // Call OnDel.
-                               for _, f := range n.onDel {
-                                       f()
-                               }
-                               n.onDel = nil
-                       }
-               }
-       }
-       r.mu.Unlock()
-
-       // Avoid deadlock.
-       if r.cacher != nil {
-               if err := r.cacher.Close(); err != nil {
-                       return err
-               }
-       }
-       return nil
-}
-
-// CloseWeak closes the 'cache map' and evict all 'cache node' from cacher, but
-// unlike Close it doesn't forcefully releases 'cache node'.
-func (r *Cache) CloseWeak() error {
-       r.mu.Lock()
-       if !r.closed {
-               r.closed = true
-       }
-       r.mu.Unlock()
-
-       // Avoid deadlock.
-       if r.cacher != nil {
-               r.cacher.EvictAll()
-               if err := r.cacher.Close(); err != nil {
-                       return err
-               }
-       }
-       return nil
-}
-
-// Node is a 'cache node'.
-type Node struct {
-       r *Cache
-
-       hash    uint32
-       ns, key uint64
-
-       mu    sync.Mutex
-       size  int
-       value Value
-
-       ref   int32
-       onDel []func()
-
-       CacheData unsafe.Pointer
-}
-
-// NS returns this 'cache node' namespace.
-func (n *Node) NS() uint64 {
-       return n.ns
-}
-
-// Key returns this 'cache node' key.
-func (n *Node) Key() uint64 {
-       return n.key
-}
-
-// Size returns this 'cache node' size.
-func (n *Node) Size() int {
-       return n.size
-}
-
-// Value returns this 'cache node' value.
-func (n *Node) Value() Value {
-       return n.value
-}
-
-// Ref returns this 'cache node' ref counter.
-func (n *Node) Ref() int32 {
-       return atomic.LoadInt32(&n.ref)
-}
-
-// GetHandle returns an handle for this 'cache node'.
-func (n *Node) GetHandle() *Handle {
-       if atomic.AddInt32(&n.ref, 1) <= 1 {
-               panic("BUG: Node.GetHandle on zero ref")
-       }
-       return &Handle{unsafe.Pointer(n)}
-}
-
-func (n *Node) unref() {
-       if atomic.AddInt32(&n.ref, -1) == 0 {
-               n.r.delete(n)
-       }
-}
-
-func (n *Node) unrefLocked() {
-       if atomic.AddInt32(&n.ref, -1) == 0 {
-               n.r.mu.RLock()
-               if !n.r.closed {
-                       n.r.delete(n)
-               }
-               n.r.mu.RUnlock()
-       }
-}
-
-// Handle is a 'cache handle' of a 'cache node'.
-type Handle struct {
-       n unsafe.Pointer // *Node
-}
-
-// Value returns the value of the 'cache node'.
-func (h *Handle) Value() Value {
-       n := (*Node)(atomic.LoadPointer(&h.n))
-       if n != nil {
-               return n.value
-       }
-       return nil
-}
-
-// Release releases this 'cache handle'.
-// It is safe to call release multiple times.
-func (h *Handle) Release() {
-       nPtr := atomic.LoadPointer(&h.n)
-       if nPtr != nil && atomic.CompareAndSwapPointer(&h.n, nPtr, nil) {
-               n := (*Node)(nPtr)
-               n.unrefLocked()
-       }
-}
-
-func murmur32(ns, key uint64, seed uint32) uint32 {
-       const (
-               m = uint32(0x5bd1e995)
-               r = 24
-       )
-
-       k1 := uint32(ns >> 32)
-       k2 := uint32(ns)
-       k3 := uint32(key >> 32)
-       k4 := uint32(key)
-
-       k1 *= m
-       k1 ^= k1 >> r
-       k1 *= m
-
-       k2 *= m
-       k2 ^= k2 >> r
-       k2 *= m
-
-       k3 *= m
-       k3 ^= k3 >> r
-       k3 *= m
-
-       k4 *= m
-       k4 ^= k4 >> r
-       k4 *= m
-
-       h := seed
-
-       h *= m
-       h ^= k1
-       h *= m
-       h ^= k2
-       h *= m
-       h ^= k3
-       h *= m
-       h ^= k4
-
-       h ^= h >> 13
-       h *= m
-       h ^= h >> 15
-
-       return h
-}