github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/state/impl_bundled_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 bundledHostState struct { 15 *hostState 16 bundles map[appdef.QName]bundle 17 bundlesLimit int 18 } 19 20 func (s *bundledHostState) CanExist(key istructs.IStateKeyBuilder) (stateValue istructs.IStateValue, ok bool, err error) { 21 bundledStorage, ok := s.bundles[key.Storage()] 22 if ok { 23 // can be already in a bundles 24 if value, ok := bundledStorage.get(key); ok { 25 // TODO later: For the optimization purposes, maybe would be wise to use e.g. AsValue() 26 // instead of BuildValue() 27 return value.value.BuildValue(), true, nil 28 } 29 } 30 31 return s.hostState.CanExist(key) 32 } 33 func (s *bundledHostState) CanExistAll(keys []istructs.IStateKeyBuilder, callback istructs.StateValueCallback) (err error) { 34 for _, k := range keys { 35 value, ok, err := s.CanExist(k) 36 if err != nil { 37 return err 38 } 39 if err = callback(k, value, ok); err != nil { 40 return err 41 } 42 } 43 return 44 } 45 func (s *bundledHostState) MustExist(key istructs.IStateKeyBuilder) (value istructs.IStateValue, err error) { 46 value, ok, err := s.CanExist(key) 47 if err != nil { 48 return 49 } 50 if !ok { 51 return nil, s.err(key, ErrNotExists) 52 } 53 return 54 } 55 func (s *bundledHostState) MustExistAll(keys []istructs.IStateKeyBuilder, callback istructs.StateValueCallback) (err error) { 56 values := make([]istructs.IStateValue, len(keys)) 57 for i, k := range keys { 58 value, err := s.MustExist(k) 59 if err != nil { 60 return err 61 } 62 values[i] = value 63 } 64 for i, value := range values { 65 if err = callback(keys[i], value, true); err != nil { 66 return err 67 } 68 } 69 return 70 } 71 func (s *bundledHostState) MustNotExist(key istructs.IStateKeyBuilder) (err error) { 72 _, ok, err := s.CanExist(key) 73 if err != nil { 74 return 75 } 76 if ok { 77 return s.err(key, ErrExists) 78 } 79 return 80 } 81 func (s *bundledHostState) MustNotExistAll(keys []istructs.IStateKeyBuilder) (err error) { 82 for _, k := range keys { 83 err = s.MustNotExist(k) 84 if err != nil { 85 return 86 } 87 } 88 return 89 } 90 func (s *bundledHostState) Read(key istructs.IStateKeyBuilder, callback istructs.ValueCallback) (err error) { 91 bundledStorage, ok := s.bundles[key.Storage()] 92 if ok { 93 if bundledStorage.containsKeysForSameEntity(key) { 94 err = s.FlushBundles() 95 if err != nil { 96 return fmt.Errorf("unable to flush on read %+v: %w", key, err) 97 } 98 } 99 } 100 return s.hostState.Read(key, callback) 101 } 102 func (s *bundledHostState) ApplyIntents() (readyToFlushBundle bool, err error) { 103 defer func() { 104 for sid := range s.intents { 105 s.intents[sid] = s.intents[sid][0:0] 106 } 107 }() 108 for sid, intents := range s.intents { 109 if len(intents) == 0 { 110 continue 111 } 112 113 err = s.withApplyBatch[sid].Validate(intents) 114 if err != nil { 115 return false, err 116 } 117 118 for _, item := range intents { 119 s.bundles[sid].put(item.key, item) 120 } 121 } 122 bundles := 0 123 for _, b := range s.bundles { 124 bundles += b.size() 125 } 126 return bundles >= s.bundlesLimit, nil 127 } 128 func (s *bundledHostState) FlushBundles() (err error) { 129 defer func() { 130 for _, b := range s.bundles { 131 b.clear() 132 } 133 }() 134 for sid, b := range s.bundles { 135 err = s.withApplyBatch[sid].ApplyBatch(b.values()) 136 if err != nil { 137 return err 138 } 139 } 140 return 141 } 142 func (s *bundledHostState) addStorage(storageName appdef.QName, storage IStateStorage, ops int) { 143 s.hostState.addStorage(storageName, storage, ops) 144 if supports(ops, S_UPDATE) || supports(ops, S_INSERT) { 145 s.bundles[storageName] = newBundle() 146 } 147 }