54 lines
1.1 KiB
Go
54 lines
1.1 KiB
Go
// +build !appengine,!windows
|
|
|
|
package fastcache
|
|
|
|
import (
|
|
"fmt"
|
|
"sync"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
const chunksPerAlloc = 1024
|
|
|
|
var (
|
|
freeChunks []*[chunkSize]byte
|
|
freeChunksLock sync.Mutex
|
|
)
|
|
|
|
func getChunk() []byte {
|
|
freeChunksLock.Lock()
|
|
if len(freeChunks) == 0 {
|
|
// Allocate offheap memory, so GOGC won't take into account cache size.
|
|
// This should reduce free memory waste.
|
|
data, err := unix.Mmap(-1, 0, chunkSize*chunksPerAlloc, unix.PROT_READ|unix.PROT_WRITE, unix.MAP_ANON|unix.MAP_PRIVATE)
|
|
if err != nil {
|
|
panic(fmt.Errorf("cannot allocate %d bytes via mmap: %s", chunkSize*chunksPerAlloc, err))
|
|
}
|
|
for len(data) > 0 {
|
|
p := (*[chunkSize]byte)(unsafe.Pointer(&data[0]))
|
|
freeChunks = append(freeChunks, p)
|
|
data = data[chunkSize:]
|
|
}
|
|
}
|
|
n := len(freeChunks) - 1
|
|
p := freeChunks[n]
|
|
freeChunks[n] = nil
|
|
freeChunks = freeChunks[:n]
|
|
freeChunksLock.Unlock()
|
|
return p[:]
|
|
}
|
|
|
|
func putChunk(chunk []byte) {
|
|
if chunk == nil {
|
|
return
|
|
}
|
|
chunk = chunk[:chunkSize]
|
|
p := (*[chunkSize]byte)(unsafe.Pointer(&chunk[0]))
|
|
|
|
freeChunksLock.Lock()
|
|
freeChunks = append(freeChunks, p)
|
|
freeChunksLock.Unlock()
|
|
}
|