Files
qb/storage/navigation.go

215 lines
5.6 KiB
Go
Raw Normal View History

2026-06-15 10:47:24 +00:00
package storage
import bin "gordenko.dev/dima/bin/little"
const (
PageNoSize = 4
)
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
type KeyComparator interface {
CompareTo(int) int
}
2026-02-10 14:02:11 +00:00
type ValueAtComparator struct {
buf []byte
timestamp uint32
}
func (s ValueAtComparator) CompareTo(elemIdx int) int {
2026-06-15 10:47:24 +00:00
var (
pos = elemIdx * IndexRecordSize
elem, _ = bin.GetUint32(s.buf[pos:])
)
if s.timestamp < elem {
return -1
} else if s.timestamp > elem {
return 1
} else {
return 0
}
2026-02-10 14:02:11 +00:00
}
2026-06-10 06:18:45 +03:00
func BinarySearch(qty int, keyComparator KeyComparator) (elemIdx int, isFound bool) {
2026-02-10 14:02:11 +00:00
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
}
}
}
2026-06-10 06:18:45 +03:00
// func getPrevPageNo(buf []byte) uint32 {
// pageNo, _ := bin.GetUint32(buf[prevPageIdx:])
// return pageNo
2026-05-31 20:01:28 +00:00
// }
2026-06-15 10:47:24 +00:00
// func GetIndexRecordsSince(buf []byte) (pageNo uint32) {
// pageNo, _ = bin.GetUint32(buf)
// return
// }
func FindPageOnIndexLevelTail(level IndexLevelTail, timestamp uint32) (pageNo uint32) {
comparator := ValueAtComparator{
buf: level.Buffer,
timestamp: timestamp,
}
elemIdx, _ := BinarySearch(level.RecordsCount, comparator)
pos := elemIdx*IndexRecordSize + 4 // timestamp size
pageNo, _ = bin.GetUint32(level.Buffer[pos:])
return
}
// func FindPageOnRecords(records []byte, timestamp uint32) (pageNo uint32) {
2026-06-10 06:18:45 +03:00
// comparator := ValueAtComparator{
2026-06-15 10:47:24 +00:00
// buf: records,
2026-06-10 06:18:45 +03:00
// timestamp: timestamp,
2026-05-31 20:01:28 +00:00
// }
2026-06-15 10:47:24 +00:00
// count := len(records) / IndexRecordSize
// elemIdx, _ := BinarySearch(count, comparator)
// pageNo, _ = bin.GetUint32(records[elemIdx*IndexRecordSize:])
2026-06-10 06:18:45 +03:00
// return
// }
2026-05-31 20:01:28 +00:00
2026-06-15 10:47:24 +00:00
func FindPageOnIndexPage(page []byte, timestamp uint32) (pageNo uint32) {
comparator := ValueAtComparator{
buf: page,
timestamp: timestamp,
}
count, _ := bin.GetUint16(page[indexRecordsCountIdx:])
elemIdx, _ := BinarySearch(int(count), comparator)
pos := elemIdx*IndexRecordSize + 4 // timestamp size
pageNo, _ = bin.GetUint32(page[pos:])
return
}
func IsZeroLevelPage(buf []byte) bool {
return buf[isZeroLevelIdx] == 1
}
// можна перевірити хвости від 0 до ... Перевіряю since кожного хвоста.
// Якщо timestamp >=, шукаю pageNo бінарним пошуком. І сторінка мені однозначно підходить.
// Якщо timestamp <, піднімаюсь вище. Якщо рівнів більше немає - until вказано за межами Range показань.
func FindPageOnIndexLevelTails(levels []IndexLevelTail, timestamp uint32) (pageNo uint32, isDataPage bool) {
for i, level := range levels {
tailSince, _ := bin.GetUint32(level.Buffer)
if timestamp >= tailSince {
pageNo = FindPageOnIndexLevelTail(level, timestamp)
return pageNo, i == 0
}
}
return
}
2026-06-10 06:18:45 +03:00
// func findPageNoIdx(buf []byte, timestamp uint32) (idx int) {
// comparator := ValueAtComparator{
// buf: buf,
// timestamp: timestamp,
2026-05-31 20:01:28 +00:00
// }
2026-06-10 06:18:45 +03:00
// qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:])
// elemIdx, _ := BinarySearch(int(qty), comparator)
// return elemIdx
2026-05-31 20:01:28 +00:00
// }
2026-06-10 06:18:45 +03:00
// func findPageNoForDeleteSince(buf []byte, since uint32) (uint32, int, int) {
// comparator := ValueAtComparator{
// buf: buf,
// timestamp: since,
// }
// qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:])
// elemIdx, _ := BinarySearch(int(qty), comparator)
// pos := elemIdx * timestampSize
// timestamp, _ := bin.GetUint32(buf[pos:])
// if timestamp == since {
// if elemIdx == 0 {
// return 0, int(qty), -1
// }
// elemIdx--
// }
// pos = indexFooterIdx - (elemIdx+1)*PageNoSize
// pageNo, _ := bin.GetUint32(buf[pos:])
// return pageNo, int(qty), elemIdx
2026-05-31 20:01:28 +00:00
// }
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
// func getLastPageNo(buf []byte) (pageNo uint32) {
// qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:])
// pos := indexFooterIdx - qty*PageNoSize
// pageNo, _ = bin.GetUint32(buf[pos:])
// return
// }
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
// func getPageNo(buf []byte, idx int) (pageNo uint32) {
// pos := indexFooterIdx - (idx+1)*PageNoSize
// pageNo, _ = bin.GetUint32(buf[pos:])
// return
// }
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
// func listPageNumbers(buf []byte) (pageNumbers []uint32) {
// qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:])
// pos := indexFooterIdx - PageNoSize
// for range qty {
// pageNo, _ := bin.GetUint32(buf[pos:])
// pageNumbers = append(pageNumbers, pageNo)
// pos -= PageNoSize
// }
// return
// }
2026-02-10 14:02:11 +00:00
2026-06-10 06:18:45 +03:00
// // include since timestamp
// func listPageNumbersSince(buf []byte, timestamp uint32) (pageNumbers []uint32) {
// comparator := ValueAtComparator{
// buf: buf,
// timestamp: timestamp,
// }
// qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:])
// elemIdx, _ := BinarySearch(int(qty), comparator)
// pos := indexFooterIdx - (elemIdx+1)*PageNoSize
// for range qty {
// pageNo, _ := bin.GetUint32(buf[pos:])
// pageNumbers = append(pageNumbers, pageNo)
// pos -= PageNoSize
// }
// return
// }
2026-02-10 14:02:11 +00:00
2026-05-31 20:01:28 +00:00
// 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
// }