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  }