github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_host_state.go (about)

     1  /*
     2   * Copyright (c) 2022-present unTill Pro, Ltd.
     3   */
     4  
     5  package state
     6  
     7  import (
     8  	"fmt"
     9  
    10  	"github.com/voedger/voedger/pkg/appdef"
    11  	"github.com/voedger/voedger/pkg/istructs"
    12  )
    13  
    14  type hostState struct {
    15  	istructs.IPkgNameResolver
    16  	appStructsFunc AppStructsFunc
    17  	name           string
    18  	storages       map[appdef.QName]IStateStorage
    19  	withGet        map[appdef.QName]IWithGet
    20  	withGetBatch   map[appdef.QName]IWithGetBatch
    21  	withRead       map[appdef.QName]IWithRead
    22  	withApplyBatch map[appdef.QName]IWithApplyBatch
    23  	withInsert     map[appdef.QName]IWithInsert
    24  	withUpdate     map[appdef.QName]IWithUpdate
    25  	intents        map[appdef.QName][]ApplyBatchItem
    26  	intentsLimit   int
    27  }
    28  
    29  func newHostState(name string, intentsLimit int, appStructsFunc AppStructsFunc) *hostState {
    30  	return &hostState{
    31  		name:           name,
    32  		storages:       make(map[appdef.QName]IStateStorage),
    33  		withGet:        make(map[appdef.QName]IWithGet),
    34  		withGetBatch:   make(map[appdef.QName]IWithGetBatch),
    35  		withRead:       make(map[appdef.QName]IWithRead),
    36  		withApplyBatch: make(map[appdef.QName]IWithApplyBatch),
    37  		withInsert:     make(map[appdef.QName]IWithInsert),
    38  		withUpdate:     make(map[appdef.QName]IWithUpdate),
    39  		intents:        make(map[appdef.QName][]ApplyBatchItem),
    40  		intentsLimit:   intentsLimit,
    41  		appStructsFunc: appStructsFunc,
    42  	}
    43  }
    44  
    45  func supports(ops int, op int) bool {
    46  	return ops&op == op
    47  }
    48  
    49  func (s hostState) App() istructs.AppQName {
    50  	return s.appStructsFunc().AppQName()
    51  }
    52  
    53  func (s hostState) PackageFullPath(localName string) string {
    54  	return s.appStructsFunc().AppDef().PackageFullPath(localName)
    55  }
    56  
    57  func (s hostState) PackageLocalName(fullPath string) string {
    58  	return s.appStructsFunc().AppDef().PackageLocalName(fullPath)
    59  }
    60  
    61  func (s hostState) PLogEvent() istructs.IPLogEvent {
    62  	panic("PLogEvent only available in actualizers")
    63  }
    64  
    65  func (s *hostState) addStorage(storageName appdef.QName, storage IStateStorage, ops int) {
    66  	s.storages[storageName] = storage
    67  	if supports(ops, S_GET) {
    68  		s.withGet[storageName] = storage.(IWithGet)
    69  	}
    70  	if supports(ops, S_GET_BATCH) {
    71  		s.withGetBatch[storageName] = storage.(IWithGetBatch)
    72  	}
    73  	if supports(ops, S_READ) {
    74  		s.withRead[storageName] = storage.(IWithRead)
    75  	}
    76  	if supports(ops, S_INSERT) {
    77  		s.withApplyBatch[storageName] = storage.(IWithApplyBatch)
    78  		s.withInsert[storageName] = storage.(IWithInsert)
    79  	}
    80  	if supports(ops, S_UPDATE) {
    81  		s.withApplyBatch[storageName] = storage.(IWithApplyBatch)
    82  		s.withUpdate[storageName] = storage.(IWithUpdate)
    83  	}
    84  }
    85  
    86  func (s *hostState) KeyBuilder(storage, entity appdef.QName) (builder istructs.IStateKeyBuilder, err error) {
    87  	// TODO later: re-using key builders
    88  	strg, ok := s.storages[storage]
    89  	if !ok {
    90  		return nil, fmt.Errorf("%s: %w", storage, ErrUnknownStorage)
    91  	}
    92  
    93  	return strg.NewKeyBuilder(entity, nil), nil
    94  }
    95  func (s *hostState) CanExist(key istructs.IStateKeyBuilder) (value istructs.IStateValue, ok bool, err error) {
    96  
    97  	get, ok := s.withGet[key.Storage()]
    98  	if ok {
    99  		value, err = get.Get(key)
   100  		return value, value != nil, err
   101  	}
   102  
   103  	items := []GetBatchItem{{key: key}}
   104  	storage, ok := s.withGetBatch[key.Storage()]
   105  	if !ok {
   106  		return nil, false, s.errOperationNotSupported(key.Storage(), ErrGetNotSupportedByStorage)
   107  	}
   108  	err = storage.GetBatch(items)
   109  	return items[0].value, items[0].value != nil, err
   110  }
   111  func (s *hostState) CanExistAll(keys []istructs.IStateKeyBuilder, callback istructs.StateValueCallback) (err error) {
   112  	batches := make(map[appdef.QName][]GetBatchItem)
   113  	for _, k := range keys {
   114  		batches[k.Storage()] = append(batches[k.Storage()], GetBatchItem{key: k})
   115  	}
   116  	for sid, batch := range batches {
   117  		getBatch, ok := s.withGetBatch[sid]
   118  		if ok { // GetBatch supported
   119  			err = getBatch.GetBatch(batch)
   120  			if err != nil {
   121  				return err
   122  			}
   123  		} else { // GetBatch not supported
   124  			get, okGet := s.withGet[sid]
   125  			if !okGet {
   126  				return s.errOperationNotSupported(sid, ErrGetNotSupportedByStorage)
   127  			}
   128  			for _, item := range batch {
   129  				item.value, err = get.Get(item.key)
   130  				if err != nil {
   131  					return err
   132  				}
   133  			}
   134  		}
   135  	}
   136  
   137  	for _, batch := range batches {
   138  		for _, item := range batch {
   139  			if err := callback(item.key, item.value, item.value != nil); err != nil {
   140  				return err
   141  			}
   142  		}
   143  	}
   144  
   145  	return nil
   146  }
   147  func (s *hostState) MustExist(key istructs.IStateKeyBuilder) (value istructs.IStateValue, err error) {
   148  	value, ok, err := s.CanExist(key)
   149  	if err != nil {
   150  		return
   151  	}
   152  	if !ok {
   153  		return nil, s.err(key, ErrNotExists)
   154  	}
   155  	return
   156  }
   157  func (s *hostState) MustExistAll(keys []istructs.IStateKeyBuilder, callback istructs.StateValueCallback) (err error) {
   158  	batches := make(map[appdef.QName][]GetBatchItem)
   159  	for _, k := range keys {
   160  		batches[k.Storage()] = append(batches[k.Storage()], GetBatchItem{key: k})
   161  	}
   162  	for sid, batch := range batches {
   163  		getBatch, ok := s.withGetBatch[sid]
   164  		if ok { // GetBatch supported
   165  			err = getBatch.GetBatch(batch)
   166  			if err != nil {
   167  				return
   168  			}
   169  			for _, item := range batch {
   170  				if item.value == nil {
   171  					return s.err(item.key, ErrNotExists)
   172  				}
   173  			}
   174  		} else { // GetBatch not supported
   175  			get, okGet := s.withGet[sid]
   176  			if !okGet {
   177  				return s.errOperationNotSupported(sid, ErrGetNotSupportedByStorage)
   178  			}
   179  			for _, item := range batch {
   180  				item.value, err = get.Get(item.key)
   181  				if err != nil {
   182  					return err
   183  				}
   184  				if item.value == nil {
   185  					return s.err(item.key, ErrNotExists)
   186  				}
   187  			}
   188  		}
   189  	}
   190  	for _, batch := range batches {
   191  		for _, item := range batch {
   192  			if err := callback(item.key, item.value, true); err != nil {
   193  				return err
   194  			}
   195  		}
   196  	}
   197  	return nil
   198  }
   199  func (s *hostState) MustNotExist(key istructs.IStateKeyBuilder) (err error) {
   200  	_, ok, err := s.CanExist(key)
   201  	if err != nil {
   202  		return
   203  	}
   204  	if ok {
   205  		return s.err(key, ErrExists)
   206  	}
   207  	return
   208  }
   209  func (s *hostState) MustNotExistAll(keys []istructs.IStateKeyBuilder) (err error) {
   210  	batches := make(map[appdef.QName][]GetBatchItem)
   211  	for _, k := range keys {
   212  		batches[k.Storage()] = append(batches[k.Storage()], GetBatchItem{key: k})
   213  	}
   214  	for sid, batch := range batches {
   215  		getBatch, ok := s.withGetBatch[sid]
   216  		if ok { // GetBatch supported
   217  			err = getBatch.GetBatch(batch)
   218  			if err != nil {
   219  				return
   220  			}
   221  			for _, item := range batch {
   222  				if item.value != nil {
   223  					return s.err(item.key, ErrExists)
   224  				}
   225  			}
   226  		} else { // GetBatch not supported
   227  			get, okGet := s.withGet[sid]
   228  			if !okGet {
   229  				return s.errOperationNotSupported(sid, ErrGetNotSupportedByStorage)
   230  			}
   231  			for _, item := range batch {
   232  				item.value, err = get.Get(item.key)
   233  				if err != nil {
   234  					return err
   235  				}
   236  				if item.value != nil {
   237  					return s.err(item.key, ErrNotExists)
   238  				}
   239  			}
   240  		}
   241  	}
   242  	return nil
   243  }
   244  func (s *hostState) Read(key istructs.IStateKeyBuilder, callback istructs.ValueCallback) (err error) {
   245  	storage, ok := s.withRead[key.Storage()]
   246  	if !ok {
   247  		return s.errOperationNotSupported(key.Storage(), ErrReadNotSupportedByStorage)
   248  	}
   249  	return storage.Read(key, callback)
   250  }
   251  func (s *hostState) FindIntent(key istructs.IStateKeyBuilder) istructs.IStateValueBuilder {
   252  	for _, item := range s.intents[key.Storage()] {
   253  		if item.key.Equals(key) {
   254  			return item.value
   255  		}
   256  	}
   257  	return nil
   258  }
   259  func (s *hostState) NewValue(key istructs.IStateKeyBuilder) (eb istructs.IStateValueBuilder, err error) {
   260  	storage, ok := s.withInsert[key.Storage()]
   261  	if !ok {
   262  		return nil, s.errOperationNotSupported(key.Storage(), ErrInsertNotSupportedByStorage)
   263  	}
   264  
   265  	if s.isIntentsFull() {
   266  		return nil, s.err(key, ErrIntentsLimitExceeded)
   267  	}
   268  
   269  	// TODO later: implement re-using of value builders
   270  	builder, err := storage.ProvideValueBuilder(key, nil)
   271  	if err != nil {
   272  		// notest
   273  		return nil, err
   274  	}
   275  	s.putToIntents(key.Storage(), key, builder)
   276  
   277  	return builder, nil
   278  }
   279  func (s *hostState) UpdateValue(key istructs.IStateKeyBuilder, existingValue istructs.IStateValue) (eb istructs.IStateValueBuilder, err error) {
   280  	storage, ok := s.withUpdate[key.Storage()]
   281  	if !ok {
   282  		return nil, s.errOperationNotSupported(key.Storage(), ErrUpdateNotSupportedByStorage)
   283  	}
   284  
   285  	if s.isIntentsFull() {
   286  		return nil, s.err(key, ErrIntentsLimitExceeded)
   287  	}
   288  
   289  	// TODO later: implement re-using of value builders
   290  	builder, err := storage.ProvideValueBuilderForUpdate(key, existingValue, nil)
   291  	if err != nil {
   292  		// notest
   293  		return nil, err
   294  	}
   295  	s.putToIntents(key.Storage(), key, builder)
   296  
   297  	return builder, nil
   298  }
   299  func (s *hostState) ValidateIntents() (err error) {
   300  	if s.isIntentsEmpty() {
   301  		return nil
   302  	}
   303  	for sid, items := range s.intents {
   304  		err = s.withApplyBatch[sid].Validate(items)
   305  		if err != nil {
   306  			return
   307  		}
   308  	}
   309  	return
   310  }
   311  func (s *hostState) ApplyIntents() (err error) {
   312  	if s.isIntentsEmpty() {
   313  		return nil
   314  	}
   315  	defer func() {
   316  		for sid := range s.intents {
   317  			s.intents[sid] = s.intents[sid][0:0]
   318  		}
   319  	}()
   320  	for sid, items := range s.intents {
   321  		err = s.withApplyBatch[sid].ApplyBatch(items)
   322  		if err != nil {
   323  			return
   324  		}
   325  	}
   326  	return nil
   327  }
   328  func (s *hostState) ClearIntents() {
   329  	for sid := range s.intents {
   330  		s.intents[sid] = s.intents[sid][0:0]
   331  	}
   332  }
   333  func (s *hostState) putToIntents(storage appdef.QName, kb istructs.IStateKeyBuilder, vb istructs.IStateValueBuilder) {
   334  	s.intents[storage] = append(s.intents[storage], ApplyBatchItem{key: kb, value: vb})
   335  }
   336  func (s *hostState) isIntentsFull() bool {
   337  	return s.isIntentsSize() >= s.intentsLimit
   338  }
   339  func (s *hostState) isIntentsEmpty() bool {
   340  	return s.isIntentsSize() == 0
   341  }
   342  func (s *hostState) isIntentsSize() int {
   343  	intentsSize := 0
   344  	for _, items := range s.intents {
   345  		intentsSize += len(items)
   346  	}
   347  	return intentsSize
   348  }
   349  func (s *hostState) errOperationNotSupported(sid appdef.QName, err error) error {
   350  	return fmt.Errorf("state %s, storage %s: %w", s.name, sid, err)
   351  }
   352  func (s *hostState) err(key istructs.IStateKeyBuilder, err error) error {
   353  	return fmt.Errorf("state %s, key %+v: %w", s.name, key, err)
   354  }