github.com/weaviate/weaviate@v1.24.6/usecases/schema/incoming_commit.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/usecases/cluster" 21 ) 22 23 func (m *Manager) handleCommit(ctx context.Context, tx *cluster.Transaction) error { 24 switch tx.Type { 25 case AddClass, RepairClass: 26 return m.handleAddClassCommit(ctx, tx) 27 case AddProperty, RepairProperty: 28 return m.handleAddPropertyCommit(ctx, tx) 29 case mergeObjectProperty: 30 return m.handleMergeObjectPropertyCommit(ctx, tx) 31 case DeleteClass: 32 return m.handleDeleteClassCommit(ctx, tx) 33 case UpdateClass: 34 return m.handleUpdateClassCommit(ctx, tx) 35 case addTenants, RepairTenant: 36 return m.handleAddTenantsCommit(ctx, tx) 37 case updateTenants: 38 return m.handleUpdateTenantsCommit(ctx, tx) 39 case deleteTenants: 40 return m.handleDeleteTenantsCommit(ctx, tx) 41 case ReadSchema: 42 return nil 43 default: 44 return errors.Errorf("unrecognized commit type %q", tx.Type) 45 } 46 } 47 48 func (m *Manager) handleTxResponse(ctx context.Context, 49 tx *cluster.Transaction, 50 ) (data []byte, err error) { 51 if tx.Type != ReadSchema { 52 return nil, nil 53 } 54 m.schemaCache.RLockGuard(func() error { 55 tx.Payload = ReadSchemaPayload{ 56 Schema: &m.schemaCache.State, 57 } 58 59 data, err = json.Marshal(tx) 60 tx.Payload = ReadSchemaPayload{} 61 return err 62 }) 63 return 64 } 65 66 func (m *Manager) handleAddClassCommit(ctx context.Context, 67 tx *cluster.Transaction, 68 ) error { 69 m.Lock() 70 pl, ok := tx.Payload.(AddClassPayload) 71 if !ok { 72 m.Unlock() 73 return errors.Errorf("expected commit payload to be AddClassPayload, but got %T", 74 tx.Payload) 75 } 76 77 err := m.handleAddClassCommitAndParse(ctx, &pl) 78 m.Unlock() 79 if err != nil { 80 return err 81 } 82 // call to migrator needs to be outside the lock that is set in addClass 83 return m.migrator.AddClass(ctx, pl.Class, pl.State) 84 } 85 86 func (m *Manager) handleAddClassCommitAndParse(ctx context.Context, pl *AddClassPayload) error { 87 if pl.Class == nil { 88 return fmt.Errorf("invalid tx: class is nil") 89 } 90 91 if pl.State == nil { 92 return fmt.Errorf("invalid tx: state is nil") 93 } 94 95 err := m.parseShardingConfig(ctx, pl.Class) 96 if err != nil { 97 return err 98 } 99 100 err = m.parseVectorIndexConfig(ctx, pl.Class) 101 if err != nil { 102 return err 103 } 104 105 pl.State.SetLocalName(m.clusterState.LocalName()) 106 return m.addClassApplyChanges(ctx, pl.Class, pl.State) 107 } 108 109 func (m *Manager) handleAddPropertyCommit(ctx context.Context, 110 tx *cluster.Transaction, 111 ) error { 112 m.Lock() 113 defer m.Unlock() 114 115 pl, ok := tx.Payload.(AddPropertyPayload) 116 if !ok { 117 return errors.Errorf("expected commit payload to be AddPropertyPayload, but got %T", 118 tx.Payload) 119 } 120 121 if pl.Property == nil { 122 return fmt.Errorf("invalid tx: property is nil") 123 } 124 125 return m.addClassPropertyApplyChanges(ctx, pl.ClassName, pl.Property) 126 } 127 128 func (m *Manager) handleMergeObjectPropertyCommit(ctx context.Context, 129 tx *cluster.Transaction, 130 ) error { 131 m.Lock() 132 defer m.Unlock() 133 134 pl, ok := tx.Payload.(MergeObjectPropertyPayload) 135 if !ok { 136 return errors.Errorf("expected commit payload to be MergeObjectPropertyPayload, but got %T", 137 tx.Payload) 138 } 139 140 if pl.Property == nil { 141 return fmt.Errorf("invalid tx: property is nil") 142 } 143 144 return m.mergeClassObjectPropertyApplyChanges(ctx, pl.ClassName, pl.Property) 145 } 146 147 func (m *Manager) handleDeleteClassCommit(ctx context.Context, 148 tx *cluster.Transaction, 149 ) error { 150 m.Lock() 151 defer m.Unlock() 152 153 pl, ok := tx.Payload.(DeleteClassPayload) 154 if !ok { 155 return errors.Errorf("expected commit payload to be DeleteClassPayload, but got %T", 156 tx.Payload) 157 } 158 159 return m.deleteClassApplyChanges(ctx, pl.ClassName) 160 } 161 162 func (m *Manager) handleUpdateClassCommit(ctx context.Context, 163 tx *cluster.Transaction, 164 ) error { 165 m.Lock() 166 defer m.Unlock() 167 168 pl, ok := tx.Payload.(UpdateClassPayload) 169 if !ok { 170 return errors.Errorf("expected commit payload to be UpdateClassPayload, but got %T", 171 tx.Payload) 172 } 173 174 if pl.Class == nil { 175 return fmt.Errorf("invalid tx: class is nil") 176 } 177 178 // note that a nil state may be valid on an update_class tx, whereas it's not 179 // valid on a add_class. That's why we're not validating whether state is set 180 // here 181 182 if err := m.parseVectorIndexConfig(ctx, pl.Class); err != nil { 183 return err 184 } 185 186 if err := m.parseShardingConfig(ctx, pl.Class); err != nil { 187 return err 188 } 189 190 return m.updateClassApplyChanges(ctx, pl.ClassName, pl.Class, pl.State) 191 } 192 193 func (m *Manager) handleAddTenantsCommit(ctx context.Context, 194 tx *cluster.Transaction, 195 ) error { 196 m.Lock() 197 defer m.Unlock() 198 199 req, ok := tx.Payload.(AddTenantsPayload) 200 if !ok { 201 return errors.Errorf("expected commit payload to be AddTenants, but got %T", 202 tx.Payload) 203 } 204 cls := m.getClassByName(req.Class) 205 if cls == nil { 206 return fmt.Errorf("class %q: %w", req.Class, ErrNotFound) 207 } 208 209 err := m.onAddTenants(ctx, cls, req) 210 if err != nil { 211 m.logger.WithField("action", "on_add_tenants"). 212 WithField("n", len(req.Tenants)). 213 WithField("class", cls.Class).Error(err) 214 } 215 return err 216 } 217 218 func (m *Manager) handleUpdateTenantsCommit(ctx context.Context, 219 tx *cluster.Transaction, 220 ) error { 221 m.Lock() 222 defer m.Unlock() 223 224 req, ok := tx.Payload.(UpdateTenantsPayload) 225 if !ok { 226 return errors.Errorf("expected commit payload to be UpdateTenants, but got %T", 227 tx.Payload) 228 } 229 cls := m.getClassByName(req.Class) 230 if cls == nil { 231 return fmt.Errorf("class %q: %w", req.Class, ErrNotFound) 232 } 233 234 err := m.onUpdateTenants(ctx, cls, req) 235 if err != nil { 236 m.logger.WithField("action", "on_add_tenants"). 237 WithField("n", len(req.Tenants)). 238 WithField("class", cls.Class).Error(err) 239 } 240 return err 241 } 242 243 func (m *Manager) handleDeleteTenantsCommit(ctx context.Context, 244 tx *cluster.Transaction, 245 ) error { 246 m.Lock() 247 defer m.Unlock() 248 249 req, ok := tx.Payload.(DeleteTenantsPayload) 250 if !ok { 251 return errors.Errorf("expected commit payload to be DeleteTenants, but got %T", 252 tx.Payload) 253 } 254 cls := m.getClassByName(req.Class) 255 if cls == nil { 256 m.logger.WithField("action", "delete_tenants"). 257 WithField("class", req.Class).Warn("class not found") 258 return nil 259 } 260 261 return m.onDeleteTenants(ctx, cls, req) 262 }