github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/shard_write_delete.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  	"context"
    16  	"fmt"
    17  
    18  	"github.com/go-openapi/strfmt"
    19  	"github.com/google/uuid"
    20  	"github.com/weaviate/weaviate/adapters/repos/db/helpers"
    21  	"github.com/weaviate/weaviate/adapters/repos/db/lsmkv"
    22  	"github.com/weaviate/weaviate/entities/storagestate"
    23  	"github.com/weaviate/weaviate/entities/storobj"
    24  )
    25  
    26  func (s *Shard) DeleteObject(ctx context.Context, id strfmt.UUID) error {
    27  	if s.isReadOnly() {
    28  		return storagestate.ErrStatusReadOnly
    29  	}
    30  
    31  	idBytes, err := uuid.MustParse(id.String()).MarshalBinary()
    32  	if err != nil {
    33  		return err
    34  	}
    35  
    36  	var docID uint64
    37  	bucket := s.store.Bucket(helpers.ObjectsBucketLSM)
    38  	existing, err := bucket.Get([]byte(idBytes))
    39  	if err != nil {
    40  		return fmt.Errorf("unexpected error on previous lookup: %w", err)
    41  	}
    42  
    43  	if existing == nil {
    44  		// nothing to do
    45  		return nil
    46  	}
    47  
    48  	// we need the doc ID so we can clean up inverted indices currently
    49  	// pointing to this object
    50  	docID, err = storobj.DocIDFromBinary(existing)
    51  	if err != nil {
    52  		return fmt.Errorf("get existing doc id from object binary: %w", err)
    53  	}
    54  
    55  	err = bucket.Delete(idBytes)
    56  	if err != nil {
    57  		return fmt.Errorf("delete object from bucket: %w", err)
    58  	}
    59  
    60  	err = s.cleanupInvertedIndexOnDelete(existing, docID)
    61  	if err != nil {
    62  		return fmt.Errorf("delete object from bucket: %w", err)
    63  	}
    64  
    65  	if err = s.store.WriteWALs(); err != nil {
    66  		return fmt.Errorf("flush all buffered WALs: %w", err)
    67  	}
    68  
    69  	if s.hasTargetVectors() {
    70  		for targetVector, queue := range s.queues {
    71  			if err = queue.Delete(docID); err != nil {
    72  				return fmt.Errorf("delete from vector index of vector %q: %w", targetVector, err)
    73  			}
    74  		}
    75  		for targetVector, vectorIndex := range s.VectorIndexes() {
    76  			if err = vectorIndex.Flush(); err != nil {
    77  				return fmt.Errorf("flush all vector index buffered WALs of vector %q: %w", targetVector, err)
    78  			}
    79  		}
    80  	} else {
    81  		if err = s.queue.Delete(docID); err != nil {
    82  			return fmt.Errorf("delete from vector index: %w", err)
    83  		}
    84  		if err = s.vectorIndex.Flush(); err != nil {
    85  			return fmt.Errorf("flush all vector index buffered WALs: %w", err)
    86  		}
    87  	}
    88  
    89  	return nil
    90  }
    91  
    92  func (s *Shard) canDeleteOne(ctx context.Context, id strfmt.UUID) (bucket *lsmkv.Bucket, obj, uid []byte, docID uint64, err error) {
    93  	if uid, err = parseBytesUUID(id); err != nil {
    94  		return nil, nil, uid, 0, err
    95  	}
    96  
    97  	bucket = s.store.Bucket(helpers.ObjectsBucketLSM)
    98  	existing, err := bucket.Get(uid)
    99  	if err != nil {
   100  		return nil, nil, uid, 0, fmt.Errorf("get previous object: %w", err)
   101  	}
   102  
   103  	if existing == nil {
   104  		return bucket, nil, uid, 0, nil
   105  	}
   106  
   107  	// we need the doc ID so we can clean up inverted indices currently
   108  	// pointing to this object
   109  	docID, err = storobj.DocIDFromBinary(existing)
   110  	if err != nil {
   111  		return bucket, nil, uid, 0, fmt.Errorf("get existing doc id from object binary: %w", err)
   112  	}
   113  	return bucket, existing, uid, docID, nil
   114  }
   115  
   116  func (s *Shard) deleteOne(ctx context.Context, bucket *lsmkv.Bucket, obj, idBytes []byte, docID uint64) error {
   117  	if obj == nil || bucket == nil {
   118  		return nil
   119  	}
   120  	err := bucket.Delete(idBytes)
   121  	if err != nil {
   122  		return fmt.Errorf("delete object from bucket: %w", err)
   123  	}
   124  
   125  	err = s.cleanupInvertedIndexOnDelete(obj, docID)
   126  	if err != nil {
   127  		return fmt.Errorf("delete object from bucket: %w", err)
   128  	}
   129  
   130  	if err = s.store.WriteWALs(); err != nil {
   131  		return fmt.Errorf("flush all buffered WALs: %w", err)
   132  	}
   133  
   134  	if s.hasTargetVectors() {
   135  		for targetVector, queue := range s.queues {
   136  			if err = queue.Delete(docID); err != nil {
   137  				return fmt.Errorf("delete from vector index of vector %q: %w", targetVector, err)
   138  			}
   139  		}
   140  		for targetVector, vectorIndex := range s.vectorIndexes {
   141  			if err = vectorIndex.Flush(); err != nil {
   142  				return fmt.Errorf("flush all vector index buffered WALs of vector %q: %w", targetVector, err)
   143  			}
   144  		}
   145  	} else {
   146  		if err = s.queue.Delete(docID); err != nil {
   147  			return fmt.Errorf("delete from vector index: %w", err)
   148  		}
   149  		if err = s.vectorIndex.Flush(); err != nil {
   150  			return fmt.Errorf("flush all vector index buffered WALs: %w", err)
   151  		}
   152  	}
   153  
   154  	return nil
   155  }
   156  
   157  func (s *Shard) cleanupInvertedIndexOnDelete(previous []byte, docID uint64) error {
   158  	previousObject, err := storobj.FromBinary(previous)
   159  	if err != nil {
   160  		return fmt.Errorf("unmarshal previous object: %w", err)
   161  	}
   162  
   163  	previousProps, previousNilProps, err := s.AnalyzeObject(previousObject)
   164  	if err != nil {
   165  		return fmt.Errorf("analyze previous object: %w", err)
   166  	}
   167  
   168  	if err = s.subtractPropLengths(previousProps); err != nil {
   169  		return fmt.Errorf("subtract prop lengths: %w", err)
   170  	}
   171  
   172  	err = s.deleteFromInvertedIndicesLSM(previousProps, previousNilProps, docID)
   173  	if err != nil {
   174  		return fmt.Errorf("put inverted indices props: %w", err)
   175  	}
   176  
   177  	if s.index.Config.TrackVectorDimensions {
   178  		if s.hasTargetVectors() {
   179  			for vecName, vec := range previousObject.Vectors {
   180  				if err = s.removeDimensionsForVecLSM(len(vec), docID, vecName); err != nil {
   181  					return fmt.Errorf("track dimensions of '%s' (delete): %w", vecName, err)
   182  				}
   183  			}
   184  		} else {
   185  			if err = s.removeDimensionsLSM(len(previousObject.Vector), docID); err != nil {
   186  				return fmt.Errorf("track dimensions (delete): %w", err)
   187  			}
   188  		}
   189  	}
   190  
   191  	return nil
   192  }