github.com/weaviate/weaviate@v1.24.6/usecases/schema/update_property.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 schema 13 14 import ( 15 "context" 16 "encoding/json" 17 "fmt" 18 19 "github.com/pkg/errors" 20 "github.com/weaviate/weaviate/entities/models" 21 "github.com/weaviate/weaviate/entities/schema" 22 ) 23 24 // MergeClassObjectProperty of an existing Class 25 // Merges NestedProperties of incoming object/object[] property into existing one 26 func (m *Manager) MergeClassObjectProperty(ctx context.Context, principal *models.Principal, 27 class string, property *models.Property, 28 ) error { 29 err := m.Authorizer.Authorize(principal, "update", "schema/objects") 30 if err != nil { 31 return err 32 } 33 34 return m.mergeClassObjectProperty(ctx, class, property) 35 } 36 37 func (m *Manager) mergeClassObjectProperty(ctx context.Context, 38 className string, prop *models.Property, 39 ) error { 40 m.Lock() 41 defer m.Unlock() 42 43 class, err := m.schemaCache.readOnlyClass(className) 44 if err != nil { 45 return err 46 } 47 prop.Name = schema.LowercaseFirstLetter(prop.Name) 48 49 // reuse setDefaults/validation/migrate methods coming from add property 50 // (empty existing names map, to validate existing updated property) 51 // TODO nested - refactor / cleanup setDefaults/validation/migrate methods 52 m.setNewPropDefaults(class, prop) 53 if err := m.validateProperty(prop, class, map[string]bool{}, false); err != nil { 54 return err 55 } 56 // migrate only after validation in completed 57 migratePropertySettings(prop) 58 59 tx, err := m.cluster.BeginTransaction(ctx, mergeObjectProperty, 60 MergeObjectPropertyPayload{className, prop}, DefaultTxTTL) 61 if err != nil { 62 // possible causes for errors could be nodes down (we expect every node to 63 // the up for a schema transaction) or concurrent transactions from other 64 // nodes 65 return errors.Wrap(err, "open cluster-wide transaction") 66 } 67 68 if err := m.cluster.CommitWriteTransaction(ctx, tx); err != nil { 69 // Only log the commit error, but do not abort the changes locally. Once 70 // we've told others to commit, we also need to commit ourselves! 71 // 72 // The idea is that if we abort our changes we are guaranteed to create an 73 // inconsistency as soon as any other node honored the commit. This would 74 // for example be the case in a 3-node cluster where node 1 is the 75 // coordinator, node 2 honored the commit and node 3 died during the commit 76 // phase. 77 // 78 // In this scenario it is far more desirable to make sure that node 1 and 79 // node 2 stay in sync, as node 3 - who may or may not have missed the 80 // update - can use a local WAL from the first TX phase to replay any 81 // missing changes once it's back. 82 m.logger.WithError(err).Errorf("not every node was able to commit") 83 } 84 85 return m.mergeClassObjectPropertyApplyChanges(ctx, className, prop) 86 } 87 88 func (m *Manager) mergeClassObjectPropertyApplyChanges(ctx context.Context, 89 className string, prop *models.Property, 90 ) error { 91 class, err := m.schemaCache.mergeObjectProperty(className, prop) 92 if err != nil { 93 return err 94 } 95 metadata, err := json.Marshal(&class) 96 if err != nil { 97 return fmt.Errorf("marshal class %s: %w", className, err) 98 } 99 m.logger. 100 WithField("action", "schema.update_object_property"). 101 Debug("saving updated schema to configuration store") 102 err = m.repo.UpdateClass(ctx, ClassPayload{Name: className, Metadata: metadata}) 103 if err != nil { 104 return err 105 } 106 m.triggerSchemaUpdateCallbacks() 107 108 // TODO nested - implement MergeObjectProperty (needed for indexing/filtering) 109 // will result in a mismatch between schema and index if function below fails 110 // return m.migrator.MergeObjectProperty(ctx, className, prop) 111 return nil 112 }