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 }