github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/vector/hnsw/commitlog/logger.go (about) 1 // _ _ 2 // __ _____ __ ___ ___ __ _| |_ ___ 3 // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \ 4 // \ V V / __/ (_| |\ V /| | (_| | || __/ 5 // \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___| 6 // 7 // Copyright © 2016 - 2024 Weaviate B.V. All rights reserved. 8 // 9 // CONTACT: hello@weaviate.io 10 // 11 12 package commitlog 13 14 import ( 15 "encoding/binary" 16 "os" 17 18 "github.com/pkg/errors" 19 "github.com/weaviate/weaviate/adapters/repos/db/vector/compressionhelpers" 20 ) 21 22 type Logger struct { 23 file *os.File 24 bufw *bufWriter 25 } 26 27 // TODO: these are duplicates with the hnsw package, unify them 28 type HnswCommitType uint8 // 256 options, plenty of room for future extensions 29 30 // TODO: these are duplicates with the hnsw package, unify them 31 const ( 32 AddNode HnswCommitType = iota 33 SetEntryPointMaxLevel 34 AddLinkAtLevel 35 ReplaceLinksAtLevel 36 AddTombstone 37 RemoveTombstone 38 ClearLinks 39 DeleteNode 40 ResetIndex 41 ClearLinksAtLevel // added in v1.8.0-rc.1, see https://github.com/weaviate/weaviate/issues/1701 42 AddLinksAtLevel // added in v1.8.0-rc.1, see https://github.com/weaviate/weaviate/issues/1705 43 AddPQ 44 ) 45 46 func NewLogger(fileName string) *Logger { 47 file, err := os.Create(fileName) 48 if err != nil { 49 panic(err) 50 } 51 52 return &Logger{file: file, bufw: NewWriter(file)} 53 } 54 55 func NewLoggerWithFile(file *os.File) *Logger { 56 return &Logger{file: file, bufw: NewWriterSize(file, 32*1024)} 57 } 58 59 func (l *Logger) SetEntryPointWithMaxLayer(id uint64, level int) error { 60 toWrite := make([]byte, 11) 61 toWrite[0] = byte(SetEntryPointMaxLevel) 62 binary.LittleEndian.PutUint64(toWrite[1:9], id) 63 binary.LittleEndian.PutUint16(toWrite[9:11], uint16(level)) 64 _, err := l.bufw.Write(toWrite) 65 return err 66 } 67 68 func (l *Logger) AddNode(id uint64, level int) error { 69 toWrite := make([]byte, 11) 70 toWrite[0] = byte(AddNode) 71 binary.LittleEndian.PutUint64(toWrite[1:9], id) 72 binary.LittleEndian.PutUint16(toWrite[9:11], uint16(level)) 73 _, err := l.bufw.Write(toWrite) 74 return err 75 } 76 77 func (l *Logger) AddPQ(data compressionhelpers.PQData) error { 78 toWrite := make([]byte, 10) 79 toWrite[0] = byte(AddPQ) 80 binary.LittleEndian.PutUint16(toWrite[1:3], data.Dimensions) 81 toWrite[3] = byte(data.EncoderType) 82 binary.LittleEndian.PutUint16(toWrite[4:6], data.Ks) 83 binary.LittleEndian.PutUint16(toWrite[6:8], data.M) 84 toWrite[8] = data.EncoderDistribution 85 if data.UseBitsEncoding { 86 toWrite[9] = 1 87 } else { 88 toWrite[9] = 0 89 } 90 91 for _, encoder := range data.Encoders { 92 toWrite = append(toWrite, encoder.ExposeDataForRestore()...) 93 } 94 _, err := l.bufw.Write(toWrite) 95 return err 96 } 97 98 func (l *Logger) AddLinkAtLevel(id uint64, level int, target uint64) error { 99 toWrite := make([]byte, 19) 100 toWrite[0] = byte(AddLinkAtLevel) 101 binary.LittleEndian.PutUint64(toWrite[1:9], id) 102 binary.LittleEndian.PutUint16(toWrite[9:11], uint16(level)) 103 binary.LittleEndian.PutUint64(toWrite[11:19], target) 104 _, err := l.bufw.Write(toWrite) 105 return err 106 } 107 108 func (l *Logger) AddLinksAtLevel(id uint64, level int, targets []uint64) error { 109 toWrite := make([]byte, 13+len(targets)*8) 110 toWrite[0] = byte(AddLinksAtLevel) 111 binary.LittleEndian.PutUint64(toWrite[1:9], id) 112 binary.LittleEndian.PutUint16(toWrite[9:11], uint16(level)) 113 binary.LittleEndian.PutUint16(toWrite[11:13], uint16(len(targets))) 114 for i, target := range targets { 115 offsetStart := 13 + i*8 116 offsetEnd := offsetStart + 8 117 binary.LittleEndian.PutUint64(toWrite[offsetStart:offsetEnd], target) 118 } 119 _, err := l.bufw.Write(toWrite) 120 return err 121 } 122 123 // chunks links in increments of 8, so that we never have to allocate a dynamic 124 // []byte size which would be guaranteed to escape to the heap 125 func (l *Logger) ReplaceLinksAtLevel(id uint64, level int, targets []uint64) error { 126 headers := make([]byte, 13) 127 headers[0] = byte(ReplaceLinksAtLevel) 128 binary.LittleEndian.PutUint64(headers[1:9], id) 129 binary.LittleEndian.PutUint16(headers[9:11], uint16(level)) 130 binary.LittleEndian.PutUint16(headers[11:13], uint16(len(targets))) 131 _, err := l.bufw.Write(headers) 132 if err != nil { 133 return errors.Wrap(err, "write headers") 134 } 135 136 i := 0 137 // chunks of 8 138 buf := make([]byte, 64) 139 for i < len(targets) { 140 if i != 0 && i%8 == 0 { 141 if _, err := l.bufw.Write(buf); err != nil { 142 return errors.Wrap(err, "write link chunk") 143 } 144 } 145 146 pos := i % 8 147 start := pos * 8 148 end := start + 8 149 binary.LittleEndian.PutUint64(buf[start:end], targets[i]) 150 151 i++ 152 } 153 154 // remainder 155 if i != 0 { 156 start := 0 157 end := i % 8 * 8 158 if end == 0 { 159 end = 64 160 } 161 162 if _, err := l.bufw.Write(buf[start:end]); err != nil { 163 return errors.Wrap(err, "write link remainder") 164 } 165 } 166 167 return nil 168 } 169 170 func (l *Logger) AddTombstone(id uint64) error { 171 toWrite := make([]byte, 9) 172 toWrite[0] = byte(AddTombstone) 173 binary.LittleEndian.PutUint64(toWrite[1:9], id) 174 _, err := l.bufw.Write(toWrite) 175 return err 176 } 177 178 func (l *Logger) RemoveTombstone(id uint64) error { 179 toWrite := make([]byte, 9) 180 toWrite[0] = byte(RemoveTombstone) 181 binary.LittleEndian.PutUint64(toWrite[1:9], id) 182 _, err := l.bufw.Write(toWrite) 183 return err 184 } 185 186 func (l *Logger) ClearLinks(id uint64) error { 187 toWrite := make([]byte, 9) 188 toWrite[0] = byte(ClearLinks) 189 binary.LittleEndian.PutUint64(toWrite[1:9], id) 190 _, err := l.bufw.Write(toWrite) 191 return err 192 } 193 194 func (l *Logger) ClearLinksAtLevel(id uint64, level uint16) error { 195 toWrite := make([]byte, 11) 196 toWrite[0] = byte(ClearLinksAtLevel) 197 binary.LittleEndian.PutUint64(toWrite[1:9], id) 198 binary.LittleEndian.PutUint16(toWrite[9:11], level) 199 _, err := l.bufw.Write(toWrite) 200 return err 201 } 202 203 func (l *Logger) DeleteNode(id uint64) error { 204 toWrite := make([]byte, 9) 205 toWrite[0] = byte(DeleteNode) 206 binary.LittleEndian.PutUint64(toWrite[1:9], id) 207 _, err := l.bufw.Write(toWrite) 208 return err 209 } 210 211 func (l *Logger) Reset() error { 212 toWrite := make([]byte, 1) 213 toWrite[0] = byte(ResetIndex) 214 _, err := l.bufw.Write(toWrite) 215 return err 216 } 217 218 func (l *Logger) FileSize() (int64, error) { 219 i, err := l.file.Stat() 220 if err != nil { 221 return -1, err 222 } 223 224 return i.Size(), nil 225 } 226 227 func (l *Logger) FileName() (string, error) { 228 i, err := l.file.Stat() 229 if err != nil { 230 return "", err 231 } 232 233 return i.Name(), nil 234 } 235 236 func (l *Logger) Flush() error { 237 return l.bufw.Flush() 238 } 239 240 func (l *Logger) Close() error { 241 if err := l.bufw.Flush(); err != nil { 242 return err 243 } 244 245 if err := l.file.Close(); err != nil { 246 return err 247 } 248 249 return nil 250 }