github.com/TrueBlocks/trueblocks-core/src/apps/chifra@v0.0.0-20241022031540-b362680128f7/pkg/cache/locations/memory.go (about) 1 package locations 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 "sync" 8 ) 9 10 // Each Storer implementation is global and thread-safe to save resources 11 // when reading/writing large number of items 12 var memoryInstance *memory 13 var memoryInitOnce sync.Once 14 15 // Helper interface that will allow us to implement memoryReadWriteCloser.Close 16 type unlocker interface { 17 unlock() 18 } 19 20 // We have to use ReadWriteCloser to conform with Storer interface 21 type memoryReadWriteCloser struct { 22 buf bytes.Buffer 23 u unlocker 24 } 25 26 func (m *memoryReadWriteCloser) Write(p []byte) (n int, err error) { 27 return m.buf.Write(p) 28 } 29 30 func (m *memoryReadWriteCloser) Read(p []byte) (n int, err error) { 31 return m.buf.Read(p) 32 } 33 34 func (m *memoryReadWriteCloser) Close() error { 35 m.u.unlock() 36 return nil 37 } 38 39 type memory struct { 40 records map[string]*memoryReadWriteCloser 41 mutex sync.Mutex 42 } 43 44 // unlock is being called by memoryReadWriteCloser.Close to unlock the mutex 45 func (l *memory) unlock() { 46 l.mutex.Unlock() 47 } 48 49 // Memory returns an instance of memory Storer, ready to be used 50 func Memory() (*memory, error) { 51 memoryInitOnce.Do(func() { 52 memoryInstance = new(memory) 53 memoryInstance.records = make(map[string]*memoryReadWriteCloser) 54 }) 55 return memoryInstance, nil 56 } 57 58 // Writer returns io.WriterCloser for the item at given path 59 func (l *memory) Writer(path string) (io.WriteCloser, error) { 60 l.mutex.Lock() 61 62 record, ok := l.records[path] 63 if !ok { 64 record = &memoryReadWriteCloser{ 65 u: l, 66 } 67 l.records[path] = record 68 } 69 70 return record, nil 71 } 72 73 // Reader returns io.ReaderCloser for the item at given path 74 func (l *memory) Reader(path string) (io.ReadCloser, error) { 75 l.mutex.Lock() 76 77 record, ok := l.records[path] 78 if !ok { 79 return nil, fmt.Errorf("%s: %w", path, ErrNotFound) 80 } 81 return record, nil 82 } 83 84 // Remove removes the item at given path 85 func (l *memory) Remove(path string) error { 86 l.mutex.Lock() 87 l.records[path] = nil 88 return nil 89 } 90 91 func (l *memory) Stat(path string) (*ItemInfo, error) { 92 l.mutex.Lock() 93 defer l.mutex.Unlock() 94 var fileSize int 95 if item, ok := l.records[path]; ok { 96 fileSize = item.buf.Len() 97 } 98 return &ItemInfo{ 99 fileSize, 100 path, 101 }, nil 102 }