github.com/leslie-fei/fastcache@v0.0.0-20240520092641-b7a9eb05711f/allocator.go (about) 1 package fastcache 2 3 import ( 4 "errors" 5 "unsafe" 6 ) 7 8 var sizeOfShardMemory = unsafe.Sizeof(shardMemory{}) 9 var ErrAllocSizeTooLarge = errors.New("alloc size too large") 10 11 type Allocator interface { 12 Alloc(size uint64) (ptr unsafe.Pointer, offset uint64, err error) 13 Base() uintptr 14 Locker() Locker 15 } 16 17 // globalAllocator 全局的内存分配, 所有的内存分配最终都是通过他分配出去 18 type globalAllocator struct { 19 mem Memory 20 metadata *Metadata 21 } 22 23 func (g *globalAllocator) Alloc(size uint64) (ptr unsafe.Pointer, offset uint64, err error) { 24 if size > g.FreeMemory() { 25 err = ErrNoSpace 26 return 27 } 28 ptr = g.mem.PtrOffset(g.metadata.Used) 29 offset = g.metadata.Used 30 g.metadata.Used += size 31 return 32 } 33 34 func (g *globalAllocator) FreeMemory() uint64 { 35 return g.metadata.TotalSize - g.metadata.Used 36 } 37 38 func (g *globalAllocator) Base() uintptr { 39 return uintptr(g.mem.Ptr()) 40 } 41 42 func (g *globalAllocator) Locker() Locker { 43 return g.metadata.GlobalLocker 44 } 45 46 type shardMemory struct { 47 offset uint64 48 size uint64 49 used uint64 50 next uint64 51 } 52 53 func (s *shardMemory) Reset() { 54 s.size = 0 55 s.offset = 0 56 s.used = 0 57 s.next = 0 58 } 59 60 func (s *shardMemory) FreeMemory() uint64 { 61 return s.size - s.used 62 } 63 64 // shardAllocator 归属于shard的内存分配, 他们都先从 globalAllocator 中分配出内存, 给shard独享 65 type shardAllocator struct { 66 global *globalAllocator 67 first uint64 68 shardMemoryLen uint32 69 growSize uint64 70 } 71 72 func (s *shardAllocator) Alloc(size uint64) (ptr unsafe.Pointer, offset uint64, err error) { 73 if size > s.growSize-uint64(sizeOfShardMemory) { 74 err = ErrAllocSizeTooLarge 75 return 76 } 77 mem := s.findShardMemory(size) 78 if mem == nil { 79 // 当shardMemory没有可以分配出size大小的块, 就需要去globalAllocator中申请 80 globalLocker := s.global.Locker() 81 globalLocker.Lock() 82 ptr, offset, err = s.global.Alloc(s.growSize) 83 globalLocker.Unlock() 84 if err != nil { 85 return 86 } 87 newMem := (*shardMemory)(ptr) 88 newMem.Reset() 89 newMem.offset = offset 90 newMem.size = s.growSize - uint64(sizeOfShardMemory) 91 if s.first == 0 { 92 s.first = newMem.offset 93 } else { 94 next := s.first 95 s.first = newMem.offset 96 newMem.next = next 97 } 98 mem = newMem 99 } 100 101 offset = mem.offset + mem.used 102 ptr = unsafe.Pointer(s.Base() + uintptr(offset)) 103 mem.used += size 104 return 105 } 106 107 func (s *shardAllocator) Base() uintptr { 108 return s.global.Base() 109 } 110 111 func (s *shardAllocator) Locker() Locker { 112 return nopLocker 113 } 114 115 // findShardMemory 找到一个可用的shardMemory 116 func (s *shardAllocator) findShardMemory(size uint64) *shardMemory { 117 offset := s.first 118 for i := 0; i < int(s.shardMemoryLen); i++ { 119 mem := (*shardMemory)(unsafe.Pointer(s.Base() + uintptr(offset))) 120 if mem.FreeMemory() >= size { 121 return mem 122 } 123 offset = mem.next 124 } 125 return nil 126 }