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  }