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  }