You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

75 lines
1.8 KiB

  1. package storage
  2. import (
  3. "fmt"
  4. "os"
  5. "sync/atomic"
  6. "github.com/hashicorp/golang-lru"
  7. "github.com/chrislusf/seaweedfs/weed/util"
  8. )
  9. var (
  10. bytesCache *lru.Cache
  11. bytesPool *util.BytesPool
  12. )
  13. /*
  14. There are one level of caching, and one level of pooling.
  15. In pooling, all []byte are fetched and returned to the pool bytesPool.
  16. In caching, the string~[]byte mapping is cached
  17. */
  18. func init() {
  19. bytesPool = util.NewBytesPool()
  20. bytesCache, _ = lru.NewWithEvict(512, func(key interface{}, value interface{}) {
  21. value.(*Block).decreaseReference()
  22. })
  23. }
  24. type Block struct {
  25. Bytes []byte
  26. refCount int32
  27. }
  28. func (block *Block) decreaseReference() {
  29. if atomic.AddInt32(&block.refCount, -1) == 0 {
  30. bytesPool.Put(block.Bytes)
  31. }
  32. }
  33. func (block *Block) increaseReference() {
  34. atomic.AddInt32(&block.refCount, 1)
  35. }
  36. // get bytes from the LRU cache of []byte first, then from the bytes pool
  37. // when []byte in LRU cache is evicted, it will be put back to the bytes pool
  38. func getBytesForFileBlock(r *os.File, offset int64, readSize int) (dataSlice []byte, block *Block, err error) {
  39. // check cache, return if found
  40. cacheKey := fmt.Sprintf("%d:%d:%d", r.Fd(), offset>>3, readSize)
  41. if obj, found := bytesCache.Get(cacheKey); found {
  42. block = obj.(*Block)
  43. block.increaseReference()
  44. dataSlice = block.Bytes[0:readSize]
  45. return dataSlice, block, nil
  46. }
  47. // get the []byte from pool
  48. b := bytesPool.Get(readSize)
  49. // refCount = 2, one by the bytesCache, one by the actual needle object
  50. block = &Block{Bytes: b, refCount: 2}
  51. dataSlice = block.Bytes[0:readSize]
  52. _, err = r.ReadAt(dataSlice, offset)
  53. bytesCache.Add(cacheKey, block)
  54. return dataSlice, block, err
  55. }
  56. func (n *Needle) ReleaseMemory() {
  57. if n.rawBlock != nil {
  58. n.rawBlock.decreaseReference()
  59. }
  60. }
  61. func ReleaseBytes(b []byte) {
  62. bytesPool.Put(b)
  63. }