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  }