github.com/matrixorigin/matrixone@v0.7.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/tidwall/btree" 28 ) 29 30 // MemoryFS is an in-memory FileService implementation 31 type MemoryFS struct { 32 name string 33 sync.RWMutex 34 tree *btree.Generic[*_MemFSEntry] 35 } 36 37 var _ FileService = new(MemoryFS) 38 39 func NewMemoryFS(name string) (*MemoryFS, error) { 40 return &MemoryFS{ 41 name: name, 42 tree: btree.NewGeneric(func(a, b *_MemFSEntry) bool { 43 return a.FilePath < b.FilePath 44 }), 45 }, nil 46 } 47 48 func (m *MemoryFS) Name() string { 49 return m.name 50 } 51 52 func (m *MemoryFS) List(ctx context.Context, dirPath string) (entries []DirEntry, err error) { 53 select { 54 case <-ctx.Done(): 55 return nil, ctx.Err() 56 default: 57 } 58 59 m.RLock() 60 defer m.RUnlock() 61 62 path, err := ParsePathAtService(dirPath, m.name) 63 if err != nil { 64 return nil, err 65 } 66 67 iter := m.tree.Iter() 68 defer iter.Release() 69 70 pivot := &_MemFSEntry{ 71 FilePath: path.File, 72 } 73 for ok := iter.Seek(pivot); ok; ok = iter.Next() { 74 item := iter.Item() 75 if !strings.HasPrefix(item.FilePath, path.File) { 76 break 77 } 78 79 relPath := strings.TrimPrefix(item.FilePath, path.File) 80 relPath = strings.Trim(relPath, "/") 81 parts := strings.Split(relPath, "/") 82 isDir := len(parts) > 1 83 name := parts[0] 84 85 if len(entries) == 0 || entries[len(entries)-1].Name != name { 86 entries = append(entries, DirEntry{ 87 IsDir: isDir, 88 Name: name, 89 Size: int64(len(item.Data)), 90 }) 91 } 92 } 93 94 return 95 } 96 97 func (m *MemoryFS) Write(ctx context.Context, vector IOVector) error { 98 select { 99 case <-ctx.Done(): 100 return ctx.Err() 101 default: 102 } 103 104 m.Lock() 105 defer m.Unlock() 106 107 path, err := ParsePathAtService(vector.FilePath, m.name) 108 if err != nil { 109 return err 110 } 111 112 pivot := &_MemFSEntry{ 113 FilePath: path.File, 114 } 115 _, ok := m.tree.Get(pivot) 116 if ok { 117 return moerr.NewFileAlreadyExistsNoCtx(path.File) 118 } 119 120 return m.write(ctx, vector) 121 } 122 123 func (m *MemoryFS) write(ctx context.Context, vector IOVector) error { 124 select { 125 case <-ctx.Done(): 126 return ctx.Err() 127 default: 128 } 129 130 path, err := ParsePathAtService(vector.FilePath, m.name) 131 if err != nil { 132 return err 133 } 134 135 if len(vector.Entries) == 0 { 136 vector.Entries = []IOEntry{ 137 { 138 Offset: 0, 139 Size: 0, 140 Data: nil, 141 }, 142 } 143 } 144 145 sort.Slice(vector.Entries, func(i, j int) bool { 146 return vector.Entries[i].Offset < vector.Entries[j].Offset 147 }) 148 149 r := newIOEntriesReader(ctx, vector.Entries) 150 data, err := io.ReadAll(r) 151 if err != nil { 152 return err 153 } 154 entry := &_MemFSEntry{ 155 FilePath: path.File, 156 Data: data, 157 } 158 m.tree.Set(entry) 159 160 return nil 161 } 162 163 func (m *MemoryFS) Read(ctx context.Context, vector *IOVector) error { 164 select { 165 case <-ctx.Done(): 166 return ctx.Err() 167 default: 168 } 169 170 path, err := ParsePathAtService(vector.FilePath, m.name) 171 if err != nil { 172 return err 173 } 174 175 if len(vector.Entries) == 0 { 176 return moerr.NewEmptyVectorNoCtx() 177 } 178 179 m.RLock() 180 defer m.RUnlock() 181 182 pivot := &_MemFSEntry{ 183 FilePath: path.File, 184 } 185 186 fsEntry, ok := m.tree.Get(pivot) 187 if !ok { 188 return moerr.NewFileNotFoundNoCtx(path.File) 189 } 190 191 for i, entry := range vector.Entries { 192 if entry.done { 193 continue 194 } 195 196 if entry.Size == 0 { 197 return moerr.NewEmptyRangeNoCtx(path.File) 198 } 199 if entry.Size < 0 { 200 entry.Size = int64(len(fsEntry.Data)) - entry.Offset 201 } 202 if entry.Size > int64(len(fsEntry.Data)) { 203 return moerr.NewUnexpectedEOFNoCtx(path.File) 204 } 205 data := fsEntry.Data[entry.Offset : entry.Offset+entry.Size] 206 207 setData := true 208 209 if w := vector.Entries[i].WriterForRead; w != nil { 210 setData = false 211 _, err := w.Write(data) 212 if err != nil { 213 return err 214 } 215 } 216 217 if ptr := vector.Entries[i].ReadCloserForRead; ptr != nil { 218 setData = false 219 *ptr = io.NopCloser(bytes.NewReader(data)) 220 } 221 222 if setData { 223 if int64(len(entry.Data)) < entry.Size || entry.Size < 0 { 224 entry.Data = data 225 if entry.Size < 0 { 226 entry.Size = int64(len(data)) 227 } 228 } else { 229 copy(entry.Data, data) 230 } 231 } 232 233 if err := entry.setObjectFromData(); err != nil { 234 return err 235 } 236 237 vector.Entries[i] = entry 238 } 239 240 return nil 241 } 242 243 func (m *MemoryFS) StatFile(ctx context.Context, filePath string) (*DirEntry, error) { 244 select { 245 case <-ctx.Done(): 246 return nil, ctx.Err() 247 default: 248 } 249 250 path, err := ParsePathAtService(filePath, m.name) 251 if err != nil { 252 return nil, err 253 } 254 255 m.RLock() 256 defer m.RUnlock() 257 258 pivot := &_MemFSEntry{ 259 FilePath: path.File, 260 } 261 262 fsEntry, ok := m.tree.Get(pivot) 263 if !ok { 264 return nil, moerr.NewFileNotFoundNoCtx(path.File) 265 } 266 267 return &DirEntry{ 268 Name: pathpkg.Base(filePath), 269 IsDir: false, 270 Size: int64(len(fsEntry.Data)), 271 }, nil 272 } 273 274 func (m *MemoryFS) Delete(ctx context.Context, filePaths ...string) error { 275 select { 276 case <-ctx.Done(): 277 return ctx.Err() 278 default: 279 } 280 281 m.Lock() 282 defer m.Unlock() 283 for _, filePath := range filePaths { 284 if err := m.deleteSingle(ctx, filePath); err != nil { 285 return err 286 } 287 } 288 return nil 289 } 290 291 func (m *MemoryFS) deleteSingle(ctx context.Context, filePath string) error { 292 293 path, err := ParsePathAtService(filePath, m.name) 294 if err != nil { 295 return err 296 } 297 298 pivot := &_MemFSEntry{ 299 FilePath: path.File, 300 } 301 m.tree.Delete(pivot) 302 303 return nil 304 } 305 306 type _MemFSEntry struct { 307 FilePath string 308 Data []byte 309 } 310 311 var _ ReplaceableFileService = new(MemoryFS) 312 313 func (m *MemoryFS) Replace(ctx context.Context, vector IOVector) error { 314 m.Lock() 315 defer m.Unlock() 316 return m.write(ctx, vector) 317 } 318 319 // mark MemoryFS as ETL-compatible to use it as ETL fs in testing 320 var _ ETLFileService = new(MemoryFS) 321 322 func (m *MemoryFS) ETLCompatible() {}