gitee.com/sasukebo/go-micro/v4@v4.7.1/store/memory.go (about)

     1  package store
     2  
     3  import (
     4  	"path/filepath"
     5  	"sort"
     6  	"strings"
     7  	"time"
     8  
     9  	"github.com/patrickmn/go-cache"
    10  	"github.com/pkg/errors"
    11  )
    12  
    13  // NewMemoryStore returns a memory store
    14  func NewMemoryStore(opts ...Option) Store {
    15  	s := &memoryStore{
    16  		options: Options{
    17  			Database: "micro",
    18  			Table:    "micro",
    19  		},
    20  		store: cache.New(cache.NoExpiration, 5*time.Minute),
    21  	}
    22  	for _, o := range opts {
    23  		o(&s.options)
    24  	}
    25  	return s
    26  }
    27  
    28  type memoryStore struct {
    29  	options Options
    30  
    31  	store *cache.Cache
    32  }
    33  
    34  type storeRecord struct {
    35  	key       string
    36  	value     []byte
    37  	metadata  map[string]interface{}
    38  	expiresAt time.Time
    39  }
    40  
    41  func (m *memoryStore) key(prefix, key string) string {
    42  	return filepath.Join(prefix, key)
    43  }
    44  
    45  func (m *memoryStore) prefix(database, table string) string {
    46  	if len(database) == 0 {
    47  		database = m.options.Database
    48  	}
    49  	if len(table) == 0 {
    50  		table = m.options.Table
    51  	}
    52  	return filepath.Join(database, table)
    53  }
    54  
    55  func (m *memoryStore) get(prefix, key string) (*Record, error) {
    56  	key = m.key(prefix, key)
    57  
    58  	var storedRecord *storeRecord
    59  	r, found := m.store.Get(key)
    60  	if !found {
    61  		return nil, ErrNotFound
    62  	}
    63  
    64  	storedRecord, ok := r.(*storeRecord)
    65  	if !ok {
    66  		return nil, errors.New("Retrieved a non *storeRecord from the cache")
    67  	}
    68  
    69  	// Copy the record on the way out
    70  	newRecord := &Record{}
    71  	newRecord.Key = strings.TrimPrefix(storedRecord.key, prefix+"/")
    72  	newRecord.Value = make([]byte, len(storedRecord.value))
    73  	newRecord.Metadata = make(map[string]interface{})
    74  
    75  	// copy the value into the new record
    76  	copy(newRecord.Value, storedRecord.value)
    77  
    78  	// check if we need to set the expiry
    79  	if !storedRecord.expiresAt.IsZero() {
    80  		newRecord.Expiry = time.Until(storedRecord.expiresAt)
    81  	}
    82  
    83  	// copy in the metadata
    84  	for k, v := range storedRecord.metadata {
    85  		newRecord.Metadata[k] = v
    86  	}
    87  
    88  	return newRecord, nil
    89  }
    90  
    91  func (m *memoryStore) set(prefix string, r *Record) {
    92  	key := m.key(prefix, r.Key)
    93  
    94  	// copy the incoming record and then
    95  	// convert the expiry in to a hard timestamp
    96  	i := &storeRecord{}
    97  	i.key = r.Key
    98  	i.value = make([]byte, len(r.Value))
    99  	i.metadata = make(map[string]interface{})
   100  
   101  	// copy the the value
   102  	copy(i.value, r.Value)
   103  
   104  	// set the expiry
   105  	if r.Expiry != 0 {
   106  		i.expiresAt = time.Now().Add(r.Expiry)
   107  	}
   108  
   109  	// set the metadata
   110  	for k, v := range r.Metadata {
   111  		i.metadata[k] = v
   112  	}
   113  
   114  	m.store.Set(key, i, r.Expiry)
   115  }
   116  
   117  func (m *memoryStore) delete(prefix, key string) {
   118  	key = m.key(prefix, key)
   119  	m.store.Delete(key)
   120  }
   121  
   122  func (m *memoryStore) list(prefix string, limit, offset uint) []string {
   123  	allItems := m.store.Items()
   124  	allKeys := make([]string, len(allItems))
   125  	i := 0
   126  
   127  	for k := range allItems {
   128  		if !strings.HasPrefix(k, prefix+"/") {
   129  			continue
   130  		}
   131  		allKeys[i] = strings.TrimPrefix(k, prefix+"/")
   132  		i++
   133  	}
   134  
   135  	if limit != 0 || offset != 0 {
   136  		sort.Slice(allKeys, func(i, j int) bool { return allKeys[i] < allKeys[j] })
   137  		min := func(i, j uint) uint {
   138  			if i < j {
   139  				return i
   140  			}
   141  			return j
   142  		}
   143  		return allKeys[offset:min(limit, uint(len(allKeys)))]
   144  	}
   145  
   146  	return allKeys
   147  }
   148  
   149  func (m *memoryStore) Close() error {
   150  	m.store.Flush()
   151  	return nil
   152  }
   153  
   154  func (m *memoryStore) Init(opts ...Option) error {
   155  	for _, o := range opts {
   156  		o(&m.options)
   157  	}
   158  	return nil
   159  }
   160  
   161  func (m *memoryStore) String() string {
   162  	return "memory"
   163  }
   164  
   165  func (m *memoryStore) Read(key string, opts ...ReadOption) ([]*Record, error) {
   166  	readOpts := ReadOptions{}
   167  	for _, o := range opts {
   168  		o(&readOpts)
   169  	}
   170  
   171  	prefix := m.prefix(readOpts.Database, readOpts.Table)
   172  
   173  	var keys []string
   174  
   175  	// Handle Prefix / suffix
   176  	if readOpts.Prefix || readOpts.Suffix {
   177  		k := m.list(prefix, 0, 0)
   178  		limit := int(readOpts.Limit)
   179  		offset := int(readOpts.Offset)
   180  
   181  		if limit > len(k) {
   182  			limit = len(k)
   183  		}
   184  
   185  		if offset > len(k) {
   186  			offset = len(k)
   187  		}
   188  
   189  		for i := offset; i < limit; i++ {
   190  			kk := k[i]
   191  
   192  			if readOpts.Prefix && !strings.HasPrefix(kk, key) {
   193  				continue
   194  			}
   195  
   196  			if readOpts.Suffix && !strings.HasSuffix(kk, key) {
   197  				continue
   198  			}
   199  
   200  			keys = append(keys, kk)
   201  		}
   202  	} else {
   203  		keys = []string{key}
   204  	}
   205  
   206  	var results []*Record
   207  
   208  	for _, k := range keys {
   209  		r, err := m.get(prefix, k)
   210  		if err != nil {
   211  			return results, err
   212  		}
   213  		results = append(results, r)
   214  	}
   215  
   216  	return results, nil
   217  }
   218  
   219  func (m *memoryStore) Write(r *Record, opts ...WriteOption) error {
   220  	writeOpts := WriteOptions{}
   221  	for _, o := range opts {
   222  		o(&writeOpts)
   223  	}
   224  
   225  	prefix := m.prefix(writeOpts.Database, writeOpts.Table)
   226  
   227  	if len(opts) > 0 {
   228  		// Copy the record before applying options, or the incoming record will be mutated
   229  		newRecord := Record{}
   230  		newRecord.Key = r.Key
   231  		newRecord.Value = make([]byte, len(r.Value))
   232  		newRecord.Metadata = make(map[string]interface{})
   233  		copy(newRecord.Value, r.Value)
   234  		newRecord.Expiry = r.Expiry
   235  
   236  		if !writeOpts.Expiry.IsZero() {
   237  			newRecord.Expiry = time.Until(writeOpts.Expiry)
   238  		}
   239  		if writeOpts.TTL != 0 {
   240  			newRecord.Expiry = writeOpts.TTL
   241  		}
   242  
   243  		for k, v := range r.Metadata {
   244  			newRecord.Metadata[k] = v
   245  		}
   246  
   247  		m.set(prefix, &newRecord)
   248  		return nil
   249  	}
   250  
   251  	// set
   252  	m.set(prefix, r)
   253  
   254  	return nil
   255  }
   256  
   257  func (m *memoryStore) Delete(key string, opts ...DeleteOption) error {
   258  	deleteOptions := DeleteOptions{}
   259  	for _, o := range opts {
   260  		o(&deleteOptions)
   261  	}
   262  
   263  	prefix := m.prefix(deleteOptions.Database, deleteOptions.Table)
   264  	m.delete(prefix, key)
   265  	return nil
   266  }
   267  
   268  func (m *memoryStore) Options() Options {
   269  	return m.options
   270  }
   271  
   272  func (m *memoryStore) List(opts ...ListOption) ([]string, error) {
   273  	listOptions := ListOptions{}
   274  
   275  	for _, o := range opts {
   276  		o(&listOptions)
   277  	}
   278  
   279  	prefix := m.prefix(listOptions.Database, listOptions.Table)
   280  	keys := m.list(prefix, listOptions.Limit, listOptions.Offset)
   281  
   282  	if len(listOptions.Prefix) > 0 {
   283  		var prefixKeys []string
   284  		for _, k := range keys {
   285  			if strings.HasPrefix(k, listOptions.Prefix) {
   286  				prefixKeys = append(prefixKeys, k)
   287  			}
   288  		}
   289  		keys = prefixKeys
   290  	}
   291  
   292  	if len(listOptions.Suffix) > 0 {
   293  		var suffixKeys []string
   294  		for _, k := range keys {
   295  			if strings.HasSuffix(k, listOptions.Suffix) {
   296  				suffixKeys = append(suffixKeys, k)
   297  			}
   298  		}
   299  		keys = suffixKeys
   300  	}
   301  
   302  	return keys, nil
   303  }