diff options
| author | chrislusf <chris.lu@gmail.com> | 2016-04-15 11:56:53 -0700 |
|---|---|---|
| committer | chrislusf <chris.lu@gmail.com> | 2016-04-15 11:56:53 -0700 |
| commit | b03e7b26b53c2c579ae13755c3fac47f67c6f40c (patch) | |
| tree | e02bc29295ee90f5a9f33065175baa54353ed55b /go/storage/needle_byte_cache.go | |
| parent | 3fb98a904bf5d67e7f51797fbee0aa7ddffb5903 (diff) | |
| download | seaweedfs-b03e7b26b53c2c579ae13755c3fac47f67c6f40c.tar.xz seaweedfs-b03e7b26b53c2c579ae13755c3fac47f67c6f40c.zip | |
add []byte caching and pooling
fixes https://github.com/chrislusf/seaweedfs/issues/211
Diffstat (limited to 'go/storage/needle_byte_cache.go')
| -rw-r--r-- | go/storage/needle_byte_cache.go | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/go/storage/needle_byte_cache.go b/go/storage/needle_byte_cache.go new file mode 100644 index 000000000..c7781917e --- /dev/null +++ b/go/storage/needle_byte_cache.go @@ -0,0 +1,70 @@ +package storage + +import ( + "fmt" + "os" + "sync/atomic" + + "github.com/hashicorp/golang-lru" + + "github.com/chrislusf/seaweedfs/go/util" +) + +var ( + bytesCache *lru.Cache + bytesPool *util.BytesPool +) + +/* +There are one level of caching, and one level of pooling. + +In pooling, all []byte are fetched and returned to the pool bytesPool. + +In caching, the string~[]byte mapping is cached, to +*/ +func init() { + bytesPool = util.NewBytesPool() + bytesCache, _ = lru.NewWithEvict(1, func(key interface{}, value interface{}) { + value.(*Block).decreaseReference() + }) +} + +type Block struct { + Bytes []byte + refCount int32 +} + +func (block *Block) decreaseReference() { + if atomic.AddInt32(&block.refCount, -1) == 0 { + bytesPool.Put(block.Bytes) + } +} +func (block *Block) increaseReference() { + atomic.AddInt32(&block.refCount, 1) +} + +// get bytes from the LRU cache of []byte first, then from the bytes pool +// when []byte in LRU cache is evicted, it will be put back to the bytes pool +func getBytesForFileBlock(r *os.File, offset int64, readSize int) (block *Block, isNew bool) { + // check cache, return if found + cacheKey := fmt.Sprintf("%d:%d:%d", r.Fd(), offset>>3, readSize) + if obj, found := bytesCache.Get(cacheKey); found { + block = obj.(*Block) + block.increaseReference() + return block, false + } + + // get the []byte from pool + b := bytesPool.Get(readSize) + // refCount = 2, one by the bytesCache, one by the actual needle object + block = &Block{Bytes: b, refCount: 2} + bytesCache.Add(cacheKey, block) + return block, true +} + +func (n *Needle) ReleaseMemory() { + n.rawBlock.decreaseReference() +} +func ReleaseBytes(b []byte) { + bytesPool.Put(b) +} |
