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 }