github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/block/mem/adapter.go (about) 1 package mem 2 3 import ( 4 "bytes" 5 "context" 6 "crypto/sha256" 7 "encoding/hex" 8 "fmt" 9 "io" 10 "net/http" 11 "net/url" 12 "sort" 13 "strings" 14 "sync" 15 "time" 16 17 "github.com/google/uuid" 18 "github.com/treeverse/lakefs/pkg/block" 19 ) 20 21 var ( 22 ErrNoDataForKey = fmt.Errorf("no data for key: %w", block.ErrDataNotFound) 23 ErrMultiPartNotFound = fmt.Errorf("multipart ID not found") 24 ErrNoPropertiesForKey = fmt.Errorf("no properties for key") 25 ) 26 27 type mpu struct { 28 id string 29 parts map[int][]byte 30 } 31 32 func newMPU() *mpu { 33 uid := uuid.New() 34 uploadID := hex.EncodeToString(uid[:]) 35 return &mpu{ 36 id: uploadID, 37 parts: make(map[int][]byte), 38 } 39 } 40 41 func (m *mpu) get() []byte { 42 buf := bytes.NewBuffer(nil) 43 keys := make([]int, len(m.parts)) 44 sort.Slice(keys, func(i, j int) bool { 45 return keys[i] < keys[j] 46 }) 47 for _, part := range keys { 48 buf.Write(m.parts[part]) 49 } 50 return buf.Bytes() 51 } 52 53 type Adapter struct { 54 data map[string][]byte 55 mpu map[string]*mpu 56 properties map[string]block.Properties 57 mutex *sync.RWMutex 58 } 59 60 func New(_ context.Context, opts ...func(a *Adapter)) *Adapter { 61 a := &Adapter{ 62 data: make(map[string][]byte), 63 mpu: make(map[string]*mpu), 64 properties: make(map[string]block.Properties), 65 mutex: &sync.RWMutex{}, 66 } 67 for _, opt := range opts { 68 opt(a) 69 } 70 return a 71 } 72 73 func getKey(obj block.ObjectPointer) string { 74 // TODO (niro): Fix mem storage path resolution 75 if obj.IdentifierType == block.IdentifierTypeFull { 76 return obj.Identifier 77 } 78 return fmt.Sprintf("%s:%s", obj.StorageNamespace, obj.Identifier) 79 } 80 81 func (a *Adapter) Put(_ context.Context, obj block.ObjectPointer, _ int64, reader io.Reader, opts block.PutOpts) error { 82 if err := verifyObjectPointer(obj); err != nil { 83 return err 84 } 85 a.mutex.Lock() 86 defer a.mutex.Unlock() 87 data, err := io.ReadAll(reader) 88 if err != nil { 89 return err 90 } 91 key := getKey(obj) 92 a.data[key] = data 93 a.properties[key] = block.Properties(opts) 94 return nil 95 } 96 97 func (a *Adapter) Get(_ context.Context, obj block.ObjectPointer, _ int64) (io.ReadCloser, error) { 98 if err := verifyObjectPointer(obj); err != nil { 99 return nil, err 100 } 101 a.mutex.RLock() 102 defer a.mutex.RUnlock() 103 key := getKey(obj) 104 data, ok := a.data[key] 105 if !ok { 106 return nil, ErrNoDataForKey 107 } 108 return io.NopCloser(bytes.NewReader(data)), nil 109 } 110 111 func verifyObjectPointer(obj block.ObjectPointer) error { 112 const prefix = "mem://" 113 if obj.StorageNamespace == "" { 114 if !strings.HasPrefix(obj.Identifier, prefix) { 115 return fmt.Errorf("mem block adapter: %w identifier: %s", block.ErrInvalidAddress, obj.Identifier) 116 } 117 } else if !strings.HasPrefix(obj.StorageNamespace, prefix) { 118 return fmt.Errorf("mem block adapter: %w storage namespace: %s", block.ErrInvalidAddress, obj.StorageNamespace) 119 } 120 return nil 121 } 122 123 func (a *Adapter) GetWalker(_ *url.URL) (block.Walker, error) { 124 return nil, fmt.Errorf("mem block adapter: %w", block.ErrOperationNotSupported) 125 } 126 127 func (a *Adapter) GetPreSignedURL(_ context.Context, obj block.ObjectPointer, _ block.PreSignMode) (string, time.Time, error) { 128 if err := verifyObjectPointer(obj); err != nil { 129 return "", time.Time{}, err 130 } 131 return "", time.Time{}, fmt.Errorf("mem block adapter: %w", block.ErrOperationNotSupported) 132 } 133 134 func (a *Adapter) Exists(_ context.Context, obj block.ObjectPointer) (bool, error) { 135 if err := verifyObjectPointer(obj); err != nil { 136 return false, err 137 } 138 a.mutex.RLock() 139 defer a.mutex.RUnlock() 140 _, ok := a.data[getKey(obj)] 141 return ok, nil 142 } 143 144 func (a *Adapter) GetRange(_ context.Context, obj block.ObjectPointer, startPosition int64, endPosition int64) (io.ReadCloser, error) { 145 if err := verifyObjectPointer(obj); err != nil { 146 return nil, err 147 } 148 a.mutex.RLock() 149 defer a.mutex.RUnlock() 150 data, ok := a.data[getKey(obj)] 151 if !ok { 152 return nil, ErrNoDataForKey 153 } 154 return io.NopCloser(io.NewSectionReader(bytes.NewReader(data), startPosition, endPosition-startPosition+1)), nil 155 } 156 157 func (a *Adapter) GetProperties(_ context.Context, obj block.ObjectPointer) (block.Properties, error) { 158 if err := verifyObjectPointer(obj); err != nil { 159 return block.Properties{}, err 160 } 161 a.mutex.RLock() 162 defer a.mutex.RUnlock() 163 props, ok := a.properties[getKey(obj)] 164 if !ok { 165 return block.Properties{}, ErrNoPropertiesForKey 166 } 167 return props, nil 168 } 169 170 func (a *Adapter) Remove(_ context.Context, obj block.ObjectPointer) error { 171 if err := verifyObjectPointer(obj); err != nil { 172 return err 173 } 174 a.mutex.Lock() 175 defer a.mutex.Unlock() 176 delete(a.data, getKey(obj)) 177 return nil 178 } 179 180 func (a *Adapter) Copy(_ context.Context, sourceObj, destinationObj block.ObjectPointer) error { 181 if err := verifyObjectPointer(sourceObj); err != nil { 182 return err 183 } 184 if err := verifyObjectPointer(destinationObj); err != nil { 185 return err 186 } 187 a.mutex.Lock() 188 defer a.mutex.Unlock() 189 destinationKey := getKey(destinationObj) 190 sourceKey := getKey(sourceObj) 191 a.data[destinationKey] = a.data[sourceKey] 192 a.properties[destinationKey] = a.properties[sourceKey] 193 return nil 194 } 195 196 func (a *Adapter) UploadCopyPart(ctx context.Context, sourceObj, _ block.ObjectPointer, uploadID string, partNumber int) (*block.UploadPartResponse, error) { 197 if err := verifyObjectPointer(sourceObj); err != nil { 198 return nil, err 199 } 200 a.mutex.Lock() 201 defer a.mutex.Unlock() 202 mpu, ok := a.mpu[uploadID] 203 if !ok { 204 return nil, ErrMultiPartNotFound 205 } 206 entry, err := a.Get(ctx, sourceObj, 0) 207 if err != nil { 208 return nil, err 209 } 210 data, err := io.ReadAll(entry) 211 if err != nil { 212 return nil, err 213 } 214 h := sha256.New() 215 _, err = h.Write(data) 216 if err != nil { 217 return nil, err 218 } 219 code := h.Sum(nil) 220 mpu.parts[partNumber] = data 221 etag := fmt.Sprintf("%x", code) 222 return &block.UploadPartResponse{ 223 ETag: etag, 224 }, nil 225 } 226 227 func (a *Adapter) UploadCopyPartRange(_ context.Context, sourceObj, _ block.ObjectPointer, uploadID string, partNumber int, startPosition, endPosition int64) (*block.UploadPartResponse, error) { 228 if err := verifyObjectPointer(sourceObj); err != nil { 229 return nil, err 230 } 231 a.mutex.Lock() 232 defer a.mutex.Unlock() 233 mpu, ok := a.mpu[uploadID] 234 if !ok { 235 return nil, ErrMultiPartNotFound 236 } 237 data, ok := a.data[getKey(sourceObj)] 238 if !ok { 239 return nil, ErrNoDataForKey 240 } 241 reader := io.NewSectionReader(bytes.NewReader(data), startPosition, endPosition-startPosition+1) 242 data, err := io.ReadAll(reader) 243 if err != nil { 244 return nil, err 245 } 246 h := sha256.New() 247 _, err = h.Write(data) 248 if err != nil { 249 return nil, err 250 } 251 code := h.Sum(nil) 252 mpu.parts[partNumber] = data 253 etag := fmt.Sprintf("%x", code) 254 return &block.UploadPartResponse{ 255 ETag: etag, 256 }, nil 257 } 258 259 func (a *Adapter) CreateMultiPartUpload(_ context.Context, obj block.ObjectPointer, _ *http.Request, _ block.CreateMultiPartUploadOpts) (*block.CreateMultiPartUploadResponse, error) { 260 if err := verifyObjectPointer(obj); err != nil { 261 return nil, err 262 } 263 a.mutex.Lock() 264 defer a.mutex.Unlock() 265 mpu := newMPU() 266 a.mpu[mpu.id] = mpu 267 return &block.CreateMultiPartUploadResponse{ 268 UploadID: mpu.id, 269 }, nil 270 } 271 272 func (a *Adapter) UploadPart(_ context.Context, obj block.ObjectPointer, _ int64, reader io.Reader, uploadID string, partNumber int) (*block.UploadPartResponse, error) { 273 if err := verifyObjectPointer(obj); err != nil { 274 return nil, err 275 } 276 a.mutex.Lock() 277 defer a.mutex.Unlock() 278 mpu, ok := a.mpu[uploadID] 279 if !ok { 280 return nil, ErrMultiPartNotFound 281 } 282 data, err := io.ReadAll(reader) 283 if err != nil { 284 return nil, err 285 } 286 h := sha256.New() 287 _, err = h.Write(data) 288 if err != nil { 289 return nil, err 290 } 291 code := h.Sum(nil) 292 mpu.parts[partNumber] = data 293 etag := fmt.Sprintf("%x", code) 294 return &block.UploadPartResponse{ 295 ETag: etag, 296 }, nil 297 } 298 299 func (a *Adapter) AbortMultiPartUpload(_ context.Context, obj block.ObjectPointer, uploadID string) error { 300 if err := verifyObjectPointer(obj); err != nil { 301 return err 302 } 303 a.mutex.Lock() 304 defer a.mutex.Unlock() 305 _, ok := a.mpu[uploadID] 306 if !ok { 307 return ErrMultiPartNotFound 308 } 309 delete(a.mpu, uploadID) 310 return nil 311 } 312 313 func (a *Adapter) CompleteMultiPartUpload(_ context.Context, obj block.ObjectPointer, uploadID string, _ *block.MultipartUploadCompletion) (*block.CompleteMultiPartUploadResponse, error) { 314 if err := verifyObjectPointer(obj); err != nil { 315 return nil, err 316 } 317 a.mutex.Lock() 318 defer a.mutex.Unlock() 319 mpu, ok := a.mpu[uploadID] 320 if !ok { 321 return nil, ErrMultiPartNotFound 322 } 323 data := mpu.get() 324 h := sha256.New() 325 _, err := h.Write(data) 326 if err != nil { 327 return nil, err 328 } 329 code := h.Sum(nil) 330 hexCode := fmt.Sprintf("%x", code) 331 a.data[getKey(obj)] = data 332 return &block.CompleteMultiPartUploadResponse{ 333 ETag: hexCode, 334 ContentLength: int64(len(data)), 335 }, nil 336 } 337 338 func (a *Adapter) BlockstoreType() string { 339 return block.BlockstoreTypeMem 340 } 341 342 func (a *Adapter) GetStorageNamespaceInfo() block.StorageNamespaceInfo { 343 info := block.DefaultStorageNamespaceInfo(block.BlockstoreTypeMem) 344 info.PreSignSupport = false 345 info.ImportSupport = false 346 return info 347 } 348 349 func (a *Adapter) ResolveNamespace(storageNamespace, key string, identifierType block.IdentifierType) (block.QualifiedKey, error) { 350 return block.DefaultResolveNamespace(storageNamespace, key, identifierType) 351 } 352 353 func (a *Adapter) RuntimeStats() map[string]string { 354 return nil 355 } 356 357 func (a *Adapter) GetPresignUploadPartURL(_ context.Context, _ block.ObjectPointer, _ string, _ int) (string, error) { 358 return "", block.ErrOperationNotSupported 359 } 360 361 func (a *Adapter) ListParts(_ context.Context, _ block.ObjectPointer, _ string, _ block.ListPartsOpts) (*block.ListPartsResponse, error) { 362 return nil, block.ErrOperationNotSupported 363 }