github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istorage/provider/impl.go (about) 1 /* 2 * Copyright (c) 2020-present unTill Pro, Ltd. 3 */ 4 5 // nolint 6 package provider 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "strings" 12 13 "github.com/voedger/voedger/pkg/istorage" 14 "github.com/voedger/voedger/pkg/istructs" 15 coreutils "github.com/voedger/voedger/pkg/utils" 16 ) 17 18 func (asp *implIAppStorageProvider) AppStorage(appQName istructs.AppQName) (storage istorage.IAppStorage, err error) { 19 asp.lock.Lock() 20 defer asp.lock.Unlock() 21 if storage, ok := asp.cache[appQName]; ok { 22 return storage, nil 23 } 24 if asp.metaStorage == nil { 25 if asp.metaStorage, err = asp.getMetaStorage(); err != nil { 26 return nil, err 27 } 28 } 29 30 exists, appStorageDesc, err := readAppStorageDesc(appQName, asp.metaStorage) 31 if err != nil { 32 return nil, err 33 } 34 if !exists { 35 if appStorageDesc, err = getNewAppStorageDesc(appQName, asp.metaStorage); err != nil { 36 return nil, err 37 } 38 } 39 40 if len(appStorageDesc.Error) == 0 && appStorageDesc.Status == istorage.AppStorageStatus_Pending { 41 if err := asp.asf.Init(asp.clarifyKeyspaceName(appStorageDesc.SafeName)); err != nil { 42 appStorageDesc.Error = err.Error() 43 } else { 44 appStorageDesc.Status = istorage.AppStorageStatus_Done 45 } 46 // possible: new SafeAppName written , but appDesc write is failed. No problem in this case because we'll just have an orphaned record 47 if err = storeAppDesc(appQName, appStorageDesc, asp.metaStorage); err != nil { 48 return nil, err 49 } 50 } 51 if len(appStorageDesc.Error) > 0 { 52 return nil, fmt.Errorf("%s: %w: %s", appStorageDesc.SafeName.String(), ErrStorageInitError, appStorageDesc.Error) 53 } 54 storage, err = asp.asf.AppStorage(asp.clarifyKeyspaceName(appStorageDesc.SafeName)) 55 if err == nil { 56 asp.cache[appQName] = storage 57 } 58 return storage, err 59 } 60 61 func (asp *implIAppStorageProvider) getMetaStorage() (istorage.IAppStorage, error) { 62 if err := asp.asf.Init(asp.clarifyKeyspaceName(istorage.SysMetaSafeName)); err != nil && err != istorage.ErrStorageAlreadyExists { 63 return nil, err 64 } 65 return asp.asf.AppStorage(asp.clarifyKeyspaceName(istorage.SysMetaSafeName)) 66 } 67 68 func (asp *implIAppStorageProvider) clarifyKeyspaceName(sn istorage.SafeAppName) istorage.SafeAppName { 69 if coreutils.IsTest() { 70 // unique safe keyspace name is generated at istorage.NewSafeAppName() 71 // uuid suffix is need in tests only avoiding the case: 72 // - go test ./... in github using Scylla 73 // - integration tests for different packages are run in simultaneously in separate processes 74 // - 2 processes using the same shared VIT config -> 2 VITs are initialized on the same keyspaces names -> conflict when e.g. creating the same logins 75 // see also getNewAppStorageDesc() below 76 newName := sn.String() + asp.suffix 77 newName = strings.ReplaceAll(newName, "-", "") 78 if len(newName) > istorage.MaxSafeNameLength { 79 newName = newName[:istorage.MaxSafeNameLength] 80 } 81 sn = istorage.NewTestSafeName(newName) 82 } 83 return sn 84 } 85 86 func storeAppDesc(appQName istructs.AppQName, appDesc istorage.AppStorageDesc, metaStorage istorage.IAppStorage) error { 87 pkBytes := []byte(appQName.String()) 88 cColsBytes := cCols_AppStorageDesc 89 appDescJSON, err := json.Marshal(&appDesc) 90 if err != nil { 91 // notest 92 return err 93 } 94 return metaStorage.Put(pkBytes, cColsBytes, appDescJSON) 95 } 96 97 func getNewAppStorageDesc(appQName istructs.AppQName, metaStorage istorage.IAppStorage) (res istorage.AppStorageDesc, err error) { 98 san, err := istorage.NewSafeAppName(appQName, func(name string) (bool, error) { 99 pkBytes := []byte(name) 100 exists, err := metaStorage.Get(pkBytes, cCols_SafeAppName, &value_SafeAppName) 101 if err != nil { 102 return false, err 103 } 104 return !exists, nil 105 }) 106 if err != nil { 107 return res, err 108 } 109 // store new SafeAppName 110 pkBytes := []byte(san.String()) 111 if err := metaStorage.Put(pkBytes, cCols_SafeAppName, value_SafeAppName); err != nil { 112 return res, err 113 } 114 return istorage.AppStorageDesc{ 115 SafeName: san, 116 Status: istorage.AppStorageStatus_Pending, 117 }, nil 118 } 119 120 func readAppStorageDesc(appQName istructs.AppQName, metaStorage istorage.IAppStorage) (ok bool, appStorageDesc istorage.AppStorageDesc, err error) { 121 pkBytes := []byte(appQName.String()) 122 appDescJSON := []byte{} 123 if ok, err = metaStorage.Get(pkBytes, cCols_AppStorageDesc, &appDescJSON); err != nil { 124 return 125 } 126 if ok { 127 err = json.Unmarshal(appDescJSON, &appStorageDesc) 128 } 129 return 130 }