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 }