package storage import ( bin "gordenko.dev/dima/bin/little" ) const ( PageNoSize = 4 ) type KeyComparator interface { CompareTo(int) int } type ValueAtComparator struct { buf []byte timestamp uint32 } func (s ValueAtComparator) CompareTo(elemIdx int) int { 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 } } func BinarySearch(qty int, keyComparator 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 } } } 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 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 } type DeleteSinceOnIndexPageResult struct { Buffer []byte RecordsCount int PageNumbers []uint32 //Idx int } func DeleteSinceOnIndexPage(buf []byte, since uint32) DeleteSinceOnIndexPageResult { comparator := ValueAtComparator{ buf: buf, timestamp: since, } count, _ := bin.GetUint16(buf[indexRecordsCountIdx:]) elemIdx, _ := BinarySearch(int(count), comparator) newbuf := make([]byte, IndexPageSize) copy(newbuf, buf[:elemIdx*IndexRecordSize]) // [0..idx) pos := elemIdx*IndexRecordSize + 4 // timestamp size deleteCount := int(count) - elemIdx var pageNumbers []uint32 for range deleteCount { pageNo, _ := bin.GetUint32(buf[pos:]) pageNumbers = append(pageNumbers, pageNo) pos += IndexRecordSize } return DeleteSinceOnIndexPageResult{ Buffer: newbuf, RecordsCount: elemIdx, PageNumbers: pageNumbers, //Idx: elemIdx, } } type DeleteOnIndexTailResult struct { RecordsCount int PageNumbers []uint32 } func DeleteSinceOnIndexTail(level IndexLevelTail, since uint32) DeleteOnIndexTailResult { comparator := ValueAtComparator{ buf: level.Buffer, timestamp: since, } elemIdx, _ := BinarySearch(level.RecordsCount, comparator) pos := elemIdx*IndexRecordSize + 4 // timestamp size deleteCount := level.RecordsCount - elemIdx var pageNumbers []uint32 for range deleteCount { pageNo, _ := bin.GetUint32(level.Buffer[pos:]) pageNumbers = append(pageNumbers, pageNo) pos += IndexRecordSize } return DeleteOnIndexTailResult{ RecordsCount: elemIdx, PageNumbers: pageNumbers, //Idx: elemIdx, } } func DeleteUntilOnIndexTail(level IndexLevelTail, until uint32) DeleteOnIndexTailResult { comparator := ValueAtComparator{ buf: level.Buffer, timestamp: until, } elemIdx, _ := BinarySearch(level.RecordsCount, comparator) pos := 4 // timestamp size deleteCount := elemIdx + 1 var pageNumbers []uint32 for range deleteCount { pageNo, _ := bin.GetUint32(level.Buffer[pos:]) pageNumbers = append(pageNumbers, pageNo) pos += IndexRecordSize } copy(level.Buffer, level.Buffer[:]) return DeleteOnIndexTailResult{ RecordsCount: elemIdx, PageNumbers: pageNumbers, //Idx: elemIdx, } } // func getPrevPageNo(buf []byte) uint32 { // pageNo, _ := bin.GetUint32(buf[prevPageIdx:]) // return pageNo // } // func GetIndexRecordsSince(buf []byte) (pageNo uint32) { // pageNo, _ = bin.GetUint32(buf) // return // } // func FindPageOnRecords(records []byte, timestamp uint32) (pageNo uint32) { // comparator := ValueAtComparator{ // buf: records, // timestamp: timestamp, // } // count := len(records) / IndexRecordSize // elemIdx, _ := BinarySearch(count, comparator) // pageNo, _ = bin.GetUint32(records[elemIdx*IndexRecordSize:]) // return // } // func findPageNoIdx(buf []byte, timestamp uint32) (idx int) { // comparator := ValueAtComparator{ // buf: buf, // timestamp: timestamp, // } // qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:]) // elemIdx, _ := BinarySearch(int(qty), comparator) // return elemIdx // } // 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 // } // func getLastPageNo(buf []byte) (pageNo uint32) { // qty, _ := bin.GetUint16(buf[indexRecordsQtyIdx:]) // pos := indexFooterIdx - qty*PageNoSize // pageNo, _ = bin.GetUint32(buf[pos:]) // return // } // func getPageNo(buf []byte, idx int) (pageNo uint32) { // pos := indexFooterIdx - (idx+1)*PageNoSize // pageNo, _ = bin.GetUint32(buf[pos:]) // return // } // from index page func ListPageNumbers(buf []byte) (pageNumbers []uint32) { count, _ := bin.GetUint16(buf[indexRecordsCountIdx:]) pos := timestampSize for range count { pageNo, _ := bin.GetUint32(buf[pos:]) pageNumbers = append(pageNumbers, pageNo) pos += IndexRecordSize } return } // // 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 // } // 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 // }