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.

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