github.com/voedger/voedger@v0.0.0-20240520144910-273e84102129/pkg/istorage/mem/impl.go (about)

     1  /*
     2   * Copyright (c) 2021-present unTill Pro, Ltd.
     3   */
     4  
     5  package mem
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"sort"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/voedger/voedger/pkg/istorage"
    15  )
    16  
    17  type appStorageFactory struct {
    18  	storages map[string]map[string]map[string][]byte
    19  }
    20  
    21  func (s *appStorageFactory) AppStorage(appName istorage.SafeAppName) (istorage.IAppStorage, error) {
    22  	storage, ok := s.storages[appName.String()]
    23  	if !ok {
    24  		return nil, istorage.ErrStorageDoesNotExist
    25  	}
    26  	return &appStorage{storage: storage}, nil
    27  }
    28  
    29  func (s *appStorageFactory) Init(appName istorage.SafeAppName) error {
    30  	if _, ok := s.storages[appName.String()]; ok {
    31  		return istorage.ErrStorageAlreadyExists
    32  	}
    33  	s.storages[appName.String()] = map[string]map[string][]byte{}
    34  	return nil
    35  }
    36  
    37  type appStorage struct {
    38  	storage      map[string]map[string][]byte
    39  	lock         sync.RWMutex
    40  	testDelayGet time.Duration // used in tests only
    41  	testDelayPut time.Duration // used in tests only
    42  }
    43  
    44  func (s *appStorage) Put(pKey []byte, cCols []byte, value []byte) (err error) {
    45  	s.lock.Lock()
    46  	defer s.lock.Unlock()
    47  	if s.testDelayPut > 0 {
    48  		time.Sleep(s.testDelayPut)
    49  	}
    50  	p := s.storage[string(pKey)]
    51  	if p == nil {
    52  		p = make(map[string][]byte)
    53  		s.storage[string(pKey)] = p
    54  	}
    55  	p[string(cCols)] = copySlice(value)
    56  	return
    57  }
    58  
    59  func (s *appStorage) PutBatch(items []istorage.BatchItem) (err error) {
    60  	s.lock.Lock()
    61  	if s.testDelayPut > 0 {
    62  		time.Sleep(s.testDelayPut)
    63  		tmpDelayPut := s.testDelayPut
    64  		s.testDelayPut = 0
    65  		defer func() {
    66  			s.lock.Lock()
    67  			s.testDelayPut = tmpDelayPut
    68  			s.lock.Unlock()
    69  		}()
    70  	}
    71  	s.lock.Unlock()
    72  	for _, item := range items {
    73  		if err = s.Put(item.PKey, item.CCols, item.Value); err != nil {
    74  			return err
    75  		}
    76  	}
    77  	return nil
    78  }
    79  
    80  func (s *appStorage) readPartSort(ctx context.Context, part map[string][]byte, startCCols, finishCCols []byte) (sortKeys []string) {
    81  	sortKeys = make([]string, 0)
    82  	for col := range part {
    83  		if ctx.Err() != nil {
    84  			return nil
    85  		}
    86  		if len(startCCols) > 0 {
    87  			if bytes.Compare(startCCols, []byte(col)) > 0 {
    88  				continue
    89  			}
    90  		}
    91  		if len(finishCCols) > 0 {
    92  			if bytes.Compare([]byte(col), finishCCols) >= 0 {
    93  				continue
    94  			}
    95  		}
    96  		sortKeys = append(sortKeys, col)
    97  	}
    98  	sort.Strings(sortKeys)
    99  	return sortKeys
   100  }
   101  
   102  func (s *appStorage) readPart(ctx context.Context, pKey []byte, startCCols, finishCCols []byte) (cCols, values [][]byte) {
   103  	s.lock.RLock()
   104  	defer s.lock.RUnlock()
   105  	var (
   106  		v  map[string][]byte
   107  		ok bool
   108  	)
   109  	if v, ok = s.storage[string(pKey)]; !ok {
   110  		return nil, nil // no such pKey
   111  	}
   112  
   113  	sortKeys := s.readPartSort(ctx, v, startCCols, finishCCols)
   114  	if sortKeys == nil {
   115  		return nil, nil
   116  	}
   117  
   118  	cCols = make([][]byte, 0)
   119  	values = make([][]byte, 0)
   120  	for _, col := range sortKeys {
   121  		if ctx.Err() != nil {
   122  			return nil, nil
   123  		}
   124  		cCols = append(cCols, copySlice([]byte(col)))
   125  		values = append(values, copySlice(v[col]))
   126  	}
   127  
   128  	return cCols, values
   129  }
   130  
   131  func (s *appStorage) Read(ctx context.Context, pKey []byte, startCCols, finishCCols []byte, cb istorage.ReadCallback) (err error) {
   132  
   133  	if (len(startCCols) > 0) && (len(finishCCols) > 0) && (bytes.Compare(startCCols, finishCCols) >= 0) {
   134  		return nil // absurd range
   135  	}
   136  
   137  	if cCols, values := s.readPart(ctx, pKey, startCCols, finishCCols); cCols != nil {
   138  		for i, cCol := range cCols {
   139  			if ctx.Err() != nil {
   140  				return nil
   141  			}
   142  			if err = cb(cCol, values[i]); err != nil {
   143  				return err
   144  			}
   145  		}
   146  	}
   147  
   148  	return nil
   149  }
   150  
   151  func (s *appStorage) Get(pKey []byte, cCols []byte, data *[]byte) (ok bool, err error) {
   152  	s.lock.RLock()
   153  	defer s.lock.RUnlock()
   154  	if s.testDelayGet > 0 {
   155  		time.Sleep(s.testDelayGet)
   156  	}
   157  	p, ok := s.storage[string(pKey)]
   158  	if !ok {
   159  		return
   160  	}
   161  	viewRecord, ok := p[string(cCols)]
   162  	if !ok {
   163  		return
   164  	}
   165  	*data = append((*data)[0:0], copySlice(viewRecord)...)
   166  	return
   167  }
   168  
   169  func (s *appStorage) GetBatch(pKey []byte, items []istorage.GetBatchItem) (err error) {
   170  	s.lock.Lock()
   171  	if s.testDelayGet > 0 {
   172  		time.Sleep(s.testDelayGet)
   173  		tmpDelayGet := s.testDelayGet
   174  		s.testDelayGet = 0
   175  		defer func() {
   176  			s.lock.Lock()
   177  			s.testDelayGet = tmpDelayGet
   178  			s.lock.Unlock()
   179  		}()
   180  	}
   181  	s.lock.Unlock()
   182  	for i := range items {
   183  		items[i].Ok, err = s.Get(pKey, items[i].CCols, items[i].Data)
   184  		if err != nil {
   185  			return
   186  		}
   187  	}
   188  	return
   189  }
   190  
   191  func copySlice(src []byte) []byte {
   192  	dst := make([]byte, len(src))
   193  	copy(dst, src)
   194  	return dst
   195  }
   196  
   197  func (s *appStorage) SetTestDelayGet(delay time.Duration) {
   198  	s.lock.Lock()
   199  	defer s.lock.Unlock()
   200  	s.testDelayGet = delay
   201  }
   202  
   203  func (s *appStorage) SetTestDelayPut(delay time.Duration) {
   204  	s.lock.Lock()
   205  	defer s.lock.Unlock()
   206  	s.testDelayPut = delay
   207  }