github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/memory_fs.go (about)

     1  // Copyright 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package fileservice
    16  
    17  import (
    18  	"bytes"
    19  	"context"
    20  	"io"
    21  	pathpkg "path"
    22  	"sort"
    23  	"strings"
    24  	"sync"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/perfcounter"
    28  	"github.com/tidwall/btree"
    29  )
    30  
    31  // MemoryFS is an in-memory FileService implementation
    32  type MemoryFS struct {
    33  	name string
    34  	sync.RWMutex
    35  	memCache        *MemCache
    36  	tree            *btree.BTreeG[*_MemFSEntry]
    37  	caches          []IOVectorCache
    38  	perfCounterSets []*perfcounter.CounterSet
    39  	asyncUpdate     bool
    40  }
    41  
    42  var _ FileService = new(MemoryFS)
    43  
    44  func NewMemoryFS(
    45  	name string,
    46  	cacheConfig CacheConfig,
    47  	perfCounterSets []*perfcounter.CounterSet,
    48  ) (*MemoryFS, error) {
    49  
    50  	fs := &MemoryFS{
    51  		name:     name,
    52  		memCache: NewMemCache(NewMemoryCache(1<<20, true, nil), nil),
    53  		tree: btree.NewBTreeG(func(a, b *_MemFSEntry) bool {
    54  			return a.FilePath < b.FilePath
    55  		}),
    56  		perfCounterSets: perfCounterSets,
    57  	}
    58  
    59  	return fs, nil
    60  }
    61  
    62  func (m *MemoryFS) Name() string {
    63  	return m.name
    64  }
    65  
    66  func (m *MemoryFS) Close() {
    67  	m.memCache.Flush()
    68  }
    69  
    70  func (m *MemoryFS) List(ctx context.Context, dirPath string) (entries []DirEntry, err error) {
    71  	select {
    72  	case <-ctx.Done():
    73  		return nil, ctx.Err()
    74  	default:
    75  	}
    76  
    77  	m.RLock()
    78  	defer m.RUnlock()
    79  
    80  	path, err := ParsePathAtService(dirPath, m.name)
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	iter := m.tree.Iter()
    86  	defer iter.Release()
    87  
    88  	pivot := &_MemFSEntry{
    89  		FilePath: path.File,
    90  	}
    91  	for ok := iter.Seek(pivot); ok; ok = iter.Next() {
    92  		item := iter.Item()
    93  		if !strings.HasPrefix(item.FilePath, path.File) {
    94  			break
    95  		}
    96  
    97  		relPath := strings.TrimPrefix(item.FilePath, path.File)
    98  		relPath = strings.Trim(relPath, "/")
    99  		parts := strings.Split(relPath, "/")
   100  		isDir := len(parts) > 1
   101  		name := parts[0]
   102  
   103  		if len(entries) == 0 || entries[len(entries)-1].Name != name {
   104  			entries = append(entries, DirEntry{
   105  				IsDir: isDir,
   106  				Name:  name,
   107  				Size:  int64(len(item.Data)),
   108  			})
   109  		}
   110  	}
   111  
   112  	return
   113  }
   114  
   115  func (m *MemoryFS) Write(ctx context.Context, vector IOVector) error {
   116  	select {
   117  	case <-ctx.Done():
   118  		return ctx.Err()
   119  	default:
   120  	}
   121  
   122  	m.Lock()
   123  	defer m.Unlock()
   124  
   125  	path, err := ParsePathAtService(vector.FilePath, m.name)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	pivot := &_MemFSEntry{
   131  		FilePath: path.File,
   132  	}
   133  	_, ok := m.tree.Get(pivot)
   134  	if ok {
   135  		return moerr.NewFileAlreadyExistsNoCtx(path.File)
   136  	}
   137  
   138  	return m.write(ctx, vector)
   139  }
   140  
   141  func (m *MemoryFS) write(ctx context.Context, vector IOVector) error {
   142  	select {
   143  	case <-ctx.Done():
   144  		return ctx.Err()
   145  	default:
   146  	}
   147  
   148  	path, err := ParsePathAtService(vector.FilePath, m.name)
   149  	if err != nil {
   150  		return err
   151  	}
   152  
   153  	if len(vector.Entries) == 0 {
   154  		vector.Entries = []IOEntry{
   155  			{
   156  				Offset: 0,
   157  				Size:   0,
   158  				Data:   nil,
   159  			},
   160  		}
   161  	}
   162  
   163  	sort.Slice(vector.Entries, func(i, j int) bool {
   164  		return vector.Entries[i].Offset < vector.Entries[j].Offset
   165  	})
   166  
   167  	r := newIOEntriesReader(ctx, vector.Entries)
   168  
   169  	data, err := io.ReadAll(r)
   170  	if err != nil {
   171  		return err
   172  	}
   173  	entry := &_MemFSEntry{
   174  		FilePath: path.File,
   175  		Data:     data,
   176  	}
   177  	m.tree.Set(entry)
   178  
   179  	return nil
   180  }
   181  
   182  func (m *MemoryFS) Read(ctx context.Context, vector *IOVector) (err error) {
   183  	select {
   184  	case <-ctx.Done():
   185  		return ctx.Err()
   186  	default:
   187  	}
   188  
   189  	for i := range vector.Entries {
   190  		vector.Entries[i].allocator = m.memCache
   191  	}
   192  	for _, cache := range m.caches {
   193  		cache := cache
   194  		if err := cache.Read(ctx, vector); err != nil {
   195  			return err
   196  		}
   197  		defer func() {
   198  			if err != nil {
   199  				return
   200  			}
   201  			err = cache.Update(ctx, vector, m.asyncUpdate)
   202  		}()
   203  	}
   204  
   205  	path, err := ParsePathAtService(vector.FilePath, m.name)
   206  	if err != nil {
   207  		return err
   208  	}
   209  
   210  	if len(vector.Entries) == 0 {
   211  		return moerr.NewEmptyVectorNoCtx()
   212  	}
   213  
   214  	m.RLock()
   215  	defer m.RUnlock()
   216  
   217  	pivot := &_MemFSEntry{
   218  		FilePath: path.File,
   219  	}
   220  
   221  	fsEntry, ok := m.tree.Get(pivot)
   222  	if !ok {
   223  		return moerr.NewFileNotFoundNoCtx(path.File)
   224  	}
   225  
   226  	for i, entry := range vector.Entries {
   227  		if entry.done {
   228  			continue
   229  		}
   230  
   231  		if entry.Size == 0 {
   232  			return moerr.NewEmptyRangeNoCtx(path.File)
   233  		}
   234  		if entry.Size < 0 {
   235  			entry.Size = int64(len(fsEntry.Data)) - entry.Offset
   236  		}
   237  		if entry.Size > int64(len(fsEntry.Data)) {
   238  			return moerr.NewUnexpectedEOFNoCtx(path.File)
   239  		}
   240  		data := fsEntry.Data[entry.Offset : entry.Offset+entry.Size]
   241  
   242  		setData := true
   243  
   244  		if w := vector.Entries[i].WriterForRead; w != nil {
   245  			setData = false
   246  			_, err := w.Write(data)
   247  			if err != nil {
   248  				return err
   249  			}
   250  		}
   251  
   252  		if ptr := vector.Entries[i].ReadCloserForRead; ptr != nil {
   253  			setData = false
   254  			*ptr = io.NopCloser(bytes.NewReader(data))
   255  		}
   256  
   257  		if setData {
   258  			if int64(len(entry.Data)) < entry.Size || entry.Size < 0 {
   259  				entry.Data = data
   260  				if entry.Size < 0 {
   261  					entry.Size = int64(len(data))
   262  				}
   263  			} else {
   264  				copy(entry.Data, data)
   265  			}
   266  		}
   267  
   268  		if err := entry.setCachedData(); err != nil {
   269  			return err
   270  		}
   271  
   272  		vector.Entries[i] = entry
   273  	}
   274  
   275  	return nil
   276  }
   277  
   278  func (m *MemoryFS) ReadCache(ctx context.Context, vector *IOVector) (err error) {
   279  	return nil
   280  }
   281  
   282  func (m *MemoryFS) StatFile(ctx context.Context, filePath string) (*DirEntry, error) {
   283  	select {
   284  	case <-ctx.Done():
   285  		return nil, ctx.Err()
   286  	default:
   287  	}
   288  
   289  	path, err := ParsePathAtService(filePath, m.name)
   290  	if err != nil {
   291  		return nil, err
   292  	}
   293  
   294  	m.RLock()
   295  	defer m.RUnlock()
   296  
   297  	pivot := &_MemFSEntry{
   298  		FilePath: path.File,
   299  	}
   300  
   301  	fsEntry, ok := m.tree.Get(pivot)
   302  	if !ok {
   303  		return nil, moerr.NewFileNotFoundNoCtx(path.File)
   304  	}
   305  
   306  	return &DirEntry{
   307  		Name:  pathpkg.Base(filePath),
   308  		IsDir: false,
   309  		Size:  int64(len(fsEntry.Data)),
   310  	}, nil
   311  }
   312  
   313  func (m *MemoryFS) PrefetchFile(ctx context.Context, filePath string) error {
   314  	return nil
   315  }
   316  
   317  func (m *MemoryFS) Delete(ctx context.Context, filePaths ...string) error {
   318  	select {
   319  	case <-ctx.Done():
   320  		return ctx.Err()
   321  	default:
   322  	}
   323  
   324  	m.Lock()
   325  	defer m.Unlock()
   326  	for _, filePath := range filePaths {
   327  		if err := m.deleteSingle(ctx, filePath); err != nil {
   328  			return err
   329  		}
   330  	}
   331  	return nil
   332  }
   333  
   334  func (m *MemoryFS) deleteSingle(ctx context.Context, filePath string) error {
   335  
   336  	path, err := ParsePathAtService(filePath, m.name)
   337  	if err != nil {
   338  		return err
   339  	}
   340  
   341  	pivot := &_MemFSEntry{
   342  		FilePath: path.File,
   343  	}
   344  	m.tree.Delete(pivot)
   345  
   346  	return nil
   347  }
   348  
   349  type _MemFSEntry struct {
   350  	FilePath string
   351  	Data     []byte
   352  }
   353  
   354  var _ ReplaceableFileService = new(MemoryFS)
   355  
   356  func (m *MemoryFS) Replace(ctx context.Context, vector IOVector) error {
   357  	m.Lock()
   358  	defer m.Unlock()
   359  	return m.write(ctx, vector)
   360  }
   361  
   362  // mark MemoryFS as ETL-compatible to use it as ETL fs in testing
   363  var _ ETLFileService = new(MemoryFS)
   364  
   365  func (m *MemoryFS) ETLCompatible() {}