github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/shard_version.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 db
    13  
    14  import (
    15  	"encoding/binary"
    16  	"os"
    17  
    18  	"github.com/pkg/errors"
    19  )
    20  
    21  // ShardCodeBaseVersion must be increased whenever there are breaking changes -
    22  // including those that we can handle in a non-breaking way
    23  // the version checker can then decide on init if it should prevent startup
    24  // completely. If it does not prevent startup, but there is still a version
    25  // mismatch, the version can be used to make specific decisions
    26  //
    27  // CHANGELOG
    28  //   - Version 1 - Everything up until Weaviate v1.10.1 inclusive
    29  //   - Version 2 - Inverted Index is now stored in an always sorted fashion and
    30  //     doc ids are stored as BigEndian. To make this backward-compatible with v1,
    31  //     doc ids need to be read and written as Little Endian. In addition, an
    32  //     additional sort step is required in three places: during a MapList call,
    33  //     during a Map Cursor and during Map Compactions. BM25 is entirely disabled
    34  //     prior to this version
    35  const (
    36  	ShardCodeBaseVersion                  = uint16(2)
    37  	ShardCodeBaseMinimumVersionForStartup = uint16(1)
    38  )
    39  
    40  type shardVersioner struct {
    41  	version uint16
    42  
    43  	// we don't need the file after initialization, but still need to track its
    44  	// path so we can delete it on .Drop()
    45  	path string
    46  }
    47  
    48  func newShardVersioner(baseDir string, dataPresent bool) (*shardVersioner, error) {
    49  	sv := &shardVersioner{}
    50  
    51  	return sv, sv.init(baseDir, dataPresent)
    52  }
    53  
    54  func (sv *shardVersioner) init(fileName string, dataPresent bool) error {
    55  	sv.path = fileName
    56  
    57  	f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0o666)
    58  	if err != nil {
    59  		return err
    60  	}
    61  
    62  	stat, err := f.Stat()
    63  	if err != nil {
    64  		return err
    65  	}
    66  
    67  	var version uint16 = 1
    68  	if stat.Size() > 0 {
    69  		// the file has existed before, we need to initialize with its content
    70  		err := binary.Read(f, binary.LittleEndian, &version)
    71  		if err != nil {
    72  			return errors.Wrap(err, "read initial version from file")
    73  		}
    74  	} else {
    75  		// if the version file does not yet exist, there are two scenarios:
    76  		// 1) We are just creating this class, which means its version is
    77  		//    ShardCodeBaseVersion.
    78  		// 2) There is data present, so we must assume it was built with a version
    79  		//    that did not yet have this versioner present, so we assume it's v1
    80  		if !dataPresent {
    81  			version = ShardCodeBaseVersion
    82  		} else {
    83  			version = 1
    84  		}
    85  
    86  		err := binary.Write(f, binary.LittleEndian, &version)
    87  		if err != nil {
    88  			return errors.Wrap(err, "write version back to file")
    89  		}
    90  
    91  		if err := f.Close(); err != nil {
    92  			return errors.Wrap(err, "close version file")
    93  		}
    94  	}
    95  
    96  	if version < ShardCodeBaseMinimumVersionForStartup {
    97  		return errors.Errorf("cannot start up shard: it was built with shard "+
    98  			"version v%d, but this version of Weaviate requires at least shard version v%d",
    99  			version, ShardCodeBaseMinimumVersionForStartup)
   100  	}
   101  
   102  	sv.version = version
   103  
   104  	return nil
   105  }
   106  
   107  func (sv *shardVersioner) Drop() error {
   108  	err := os.Remove(sv.path)
   109  	if err != nil {
   110  		return errors.Wrap(err, "drop versioner file")
   111  	}
   112  	return nil
   113  }
   114  
   115  func (sv *shardVersioner) Version() uint16 {
   116  	return sv.version
   117  }