71 lines
2.2 KiB
Go
71 lines
2.2 KiB
Go
|
package bigcache
|
||
|
|
||
|
import (
|
||
|
"encoding/binary"
|
||
|
"reflect"
|
||
|
"unsafe"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
timestampSizeInBytes = 8 // Number of bytes used for timestamp
|
||
|
hashSizeInBytes = 8 // Number of bytes used for hash
|
||
|
keySizeInBytes = 2 // Number of bytes used for size of entry key
|
||
|
headersSizeInBytes = timestampSizeInBytes + hashSizeInBytes + keySizeInBytes // Number of bytes used for all headers
|
||
|
)
|
||
|
|
||
|
func wrapEntry(timestamp uint64, hash uint64, key string, entry []byte, buffer *[]byte) []byte {
|
||
|
keyLength := len(key)
|
||
|
blobLength := len(entry) + headersSizeInBytes + keyLength
|
||
|
|
||
|
if blobLength > len(*buffer) {
|
||
|
*buffer = make([]byte, blobLength)
|
||
|
}
|
||
|
blob := *buffer
|
||
|
|
||
|
binary.LittleEndian.PutUint64(blob, timestamp)
|
||
|
binary.LittleEndian.PutUint64(blob[timestampSizeInBytes:], hash)
|
||
|
binary.LittleEndian.PutUint16(blob[timestampSizeInBytes+hashSizeInBytes:], uint16(keyLength))
|
||
|
copy(blob[headersSizeInBytes:], key)
|
||
|
copy(blob[headersSizeInBytes+keyLength:], entry)
|
||
|
|
||
|
return blob[:blobLength]
|
||
|
}
|
||
|
|
||
|
func readEntry(data []byte) []byte {
|
||
|
length := binary.LittleEndian.Uint16(data[timestampSizeInBytes+hashSizeInBytes:])
|
||
|
|
||
|
// copy on read
|
||
|
dst := make([]byte, len(data)-int(headersSizeInBytes+length))
|
||
|
copy(dst, data[headersSizeInBytes+length:])
|
||
|
|
||
|
return dst
|
||
|
}
|
||
|
|
||
|
func readTimestampFromEntry(data []byte) uint64 {
|
||
|
return binary.LittleEndian.Uint64(data)
|
||
|
}
|
||
|
|
||
|
func readKeyFromEntry(data []byte) string {
|
||
|
length := binary.LittleEndian.Uint16(data[timestampSizeInBytes+hashSizeInBytes:])
|
||
|
|
||
|
// copy on read
|
||
|
dst := make([]byte, length)
|
||
|
copy(dst, data[headersSizeInBytes:headersSizeInBytes+length])
|
||
|
|
||
|
return bytesToString(dst)
|
||
|
}
|
||
|
|
||
|
func bytesToString(b []byte) string {
|
||
|
bytesHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
|
||
|
strHeader := reflect.StringHeader{Data: bytesHeader.Data, Len: bytesHeader.Len}
|
||
|
return *(*string)(unsafe.Pointer(&strHeader))
|
||
|
}
|
||
|
|
||
|
func readHashFromEntry(data []byte) uint64 {
|
||
|
return binary.LittleEndian.Uint64(data[timestampSizeInBytes:])
|
||
|
}
|
||
|
|
||
|
func resetKeyFromEntry(data []byte) {
|
||
|
binary.LittleEndian.PutUint64(data[timestampSizeInBytes:], 0)
|
||
|
}
|