package atree import ( "gordenko.dev/dima/qb/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 ChunksToNotLinkedDataPageReq struct { // // PrevPageNo uint32 // TimestampsChunks [][]byte // TimestampsSize uint16 // ValuesChunks [][]byte // ValuesSize uint16 // } // func ChunksToNotLinkedDataPage(buf []byte, req ChunksToNotLinkedDataPageReq) { // 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 // } // } // } // 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 // }