Spaces:
Running
Running
File size: 3,589 Bytes
b110593 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
// _ _
// __ _____ __ ___ ___ __ _| |_ ___
// \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
// \ V V / __/ (_| |\ V /| | (_| | || __/
// \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
//
// Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
//
// CONTACT: [email protected]
//
package segmentindex
import (
"bufio"
"bytes"
"encoding/binary"
"fmt"
"io"
)
// HeaderSize describes the general offset in a segment until the data
// starts, it is composed of 2 bytes for level, 2 bytes for version,
// 2 bytes for secondary index count, 2 bytes for strategy, 8 bytes
// for the pointer to the index part
const HeaderSize = 16
type Header struct {
Level uint16
Version uint16
SecondaryIndices uint16
Strategy Strategy
IndexStart uint64
}
func (h *Header) WriteTo(w io.Writer) (int64, error) {
if err := binary.Write(w, binary.LittleEndian, &h.Level); err != nil {
return -1, err
}
if err := binary.Write(w, binary.LittleEndian, &h.Version); err != nil {
return -1, err
}
if err := binary.Write(w, binary.LittleEndian, &h.SecondaryIndices); err != nil {
return -1, err
}
if err := binary.Write(w, binary.LittleEndian, h.Strategy); err != nil {
return -1, err
}
if err := binary.Write(w, binary.LittleEndian, &h.IndexStart); err != nil {
return -1, err
}
return int64(HeaderSize), nil
}
func (h *Header) PrimaryIndex(source []byte) ([]byte, error) {
if h.SecondaryIndices == 0 {
return source[h.IndexStart:], nil
}
offsets, err := h.parseSecondaryIndexOffsets(
source[h.IndexStart:h.secondaryIndexOffsetsEnd()])
if err != nil {
return nil, err
}
// the beginning of the first secondary is also the end of the primary
end := offsets[0]
return source[h.secondaryIndexOffsetsEnd():end], nil
}
func (h *Header) secondaryIndexOffsetsEnd() uint64 {
return h.IndexStart + (uint64(h.SecondaryIndices) * 8)
}
func (h *Header) parseSecondaryIndexOffsets(source []byte) ([]uint64, error) {
r := bufio.NewReader(bytes.NewReader(source))
offsets := make([]uint64, h.SecondaryIndices)
if err := binary.Read(r, binary.LittleEndian, &offsets); err != nil {
return nil, err
}
return offsets, nil
}
func (h *Header) SecondaryIndex(source []byte, indexID uint16) ([]byte, error) {
if indexID >= h.SecondaryIndices {
return nil, fmt.Errorf("retrieve index %d with len %d",
indexID, h.SecondaryIndices)
}
offsets, err := h.parseSecondaryIndexOffsets(
source[h.IndexStart:h.secondaryIndexOffsetsEnd()])
if err != nil {
return nil, err
}
start := offsets[indexID]
if indexID == h.SecondaryIndices-1 {
// this is the last index, return until EOF
return source[start:], nil
}
end := offsets[indexID+1]
return source[start:end], nil
}
func ParseHeader(r io.Reader) (*Header, error) {
out := &Header{}
if err := binary.Read(r, binary.LittleEndian, &out.Level); err != nil {
return nil, err
}
if err := binary.Read(r, binary.LittleEndian, &out.Version); err != nil {
return nil, err
}
if err := binary.Read(r, binary.LittleEndian, &out.SecondaryIndices); err != nil {
return nil, err
}
if out.Version != 0 {
return nil, fmt.Errorf("unsupported version %d", out.Version)
}
if err := binary.Read(r, binary.LittleEndian, &out.Strategy); err != nil {
return nil, err
}
if err := binary.Read(r, binary.LittleEndian, &out.IndexStart); err != nil {
return nil, err
}
return out, nil
}
|