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  }