спеціалізована СУБД для зберігання та обробки показань датчиків та лічильників
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.
 
 
diploma/atree/misc.go

214 lines
4.7 KiB

package atree
import (
"hash/crc32"
"gordenko.dev/dima/diploma/bin"
)
type ValueAtComparator struct {
buf []byte
timestamp uint32
}
func (s ValueAtComparator) CompareTo(elemIdx int) int {
var (
pos = elemIdx * timestampSize
elem = bin.GetUint32(s.buf[pos:])
)
if s.timestamp < elem {
return -1
} else if s.timestamp > elem {
return 1
} else {
return 0
}
}
func BinarySearch(qty int, keyComparator bin.KeyComparator) (elemIdx int, isFound bool) {
if qty == 0 {
return
}
a := 0
b := qty - 1
for {
var (
elemIdx = (b-a)/2 + a
code = keyComparator.CompareTo(elemIdx)
)
if code == 1 {
a = elemIdx + 1
if a > b {
return elemIdx, false // +1
}
} else if code == -1 {
b = elemIdx - 1
if b < a {
if elemIdx == 0 {
return 0, false
} else {
return elemIdx - 1, false
}
}
} else {
return elemIdx, true
}
}
}
type chunksToDataPageReq struct {
PrevPageNo uint32
TimestampsChunks [][]byte
TimestampsSize uint16
ValuesChunks [][]byte
ValuesSize uint16
}
func chunksToDataPage(buf []byte, req chunksToDataPageReq) {
bin.PutUint32(buf[prevPageIdx:], req.PrevPageNo)
bin.PutUint16(buf[timestampsSizeIdx:], req.TimestampsSize)
bin.PutUint16(buf[valuesSizeIdx:], req.ValuesSize)
var (
remainingSize = int(req.TimestampsSize)
pos = 0
)
for _, chunk := range req.TimestampsChunks {
if remainingSize >= len(chunk) {
copy(buf[pos:], chunk)
remainingSize -= len(chunk)
pos += len(chunk)
} else {
copy(buf[pos:], chunk[:remainingSize])
break
}
}
remainingSize = int(req.ValuesSize)
pos = int(req.TimestampsSize)
for _, chunk := range req.ValuesChunks {
if remainingSize >= len(chunk) {
copy(buf[pos:], chunk)
remainingSize -= len(chunk)
pos += len(chunk)
} else {
copy(buf[pos:], chunk[:remainingSize])
break
}
}
bin.PutUint32(buf[dataCRC32Idx:], crc32.ChecksumIEEE(buf[:dataCRC32Idx]))
}
func setPrevPageNo(buf []byte, pageNo uint32) {
bin.PutUint32(buf[prevPageIdx:], pageNo)
}
func getPrevPageNo(buf []byte) uint32 {
return bin.GetUint32(buf[prevPageIdx:])
}
func findPageNo(buf []byte, timestamp uint32) (pageNo uint32) {
var (
qty = bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
comparator = ValueAtComparator{
buf: buf,
timestamp: timestamp,
}
)
elemIdx, _ := BinarySearch(qty, comparator)
pos := indexFooterIdx - (elemIdx+1)*PageNoSize
return bin.GetUint32(buf[pos:])
}
func findPageNoIdx(buf []byte, timestamp uint32) (idx int) {
var (
qty = bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
comparator = ValueAtComparator{
buf: buf,
timestamp: timestamp,
}
)
elemIdx, _ := BinarySearch(qty, comparator)
return elemIdx
}
func findPageNoForDeleteSince(buf []byte, since uint32) (uint32, int, int) {
var (
qty = bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
comparator = ValueAtComparator{
buf: buf,
timestamp: since,
}
)
elemIdx, _ := BinarySearch(qty, comparator)
pos := elemIdx * timestampSize
timestamp := bin.GetUint32(buf[pos:])
if timestamp == since {
if elemIdx == 0 {
return 0, qty, -1
}
elemIdx--
}
pos = indexFooterIdx - (elemIdx+1)*PageNoSize
return bin.GetUint32(buf[pos:]), qty, elemIdx
}
func getLastPageNo(buf []byte) (pageNo uint32) {
qty := bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
pos := indexFooterIdx - qty*PageNoSize
return bin.GetUint32(buf[pos:])
}
func getPageNo(buf []byte, idx int) (pageNo uint32) {
pos := indexFooterIdx - (idx+1)*PageNoSize
return bin.GetUint32(buf[pos:])
}
func listPageNumbers(buf []byte) (pageNumbers []uint32) {
qty := bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
pos := indexFooterIdx - PageNoSize
for range qty {
pageNumbers = append(pageNumbers, bin.GetUint32(buf[pos:]))
pos -= PageNoSize
}
return
}
// include since timestamp
func listPageNumbersSince(buf []byte, timestamp uint32) (pageNumbers []uint32) {
var (
qty = bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
comparator = ValueAtComparator{
buf: buf,
timestamp: timestamp,
}
)
elemIdx, _ := BinarySearch(qty, comparator)
pos := indexFooterIdx - (elemIdx+1)*PageNoSize
for range qty {
pageNumbers = append(pageNumbers, bin.GetUint32(buf[pos:]))
pos -= PageNoSize
}
return
}
func getSince(buf []byte) uint32 {
return bin.GetUint32(buf[0:])
}
func appendPair(buf []byte, timestamp uint32, pageNo uint32) bool {
qty := bin.GetUint16AsInt(buf[indexRecordsQtyIdx:])
free := indexFooterIdx - qty*pairSize
if free < pairSize {
return false
}
pos := qty * timestampSize
bin.PutUint32(buf[pos:], timestamp)
pos = indexFooterIdx - (qty+1)*PageNoSize
bin.PutUint32(buf[pos:], pageNo)
bin.PutIntAsUint16(buf[indexRecordsQtyIdx:], qty+1)
return true
}