github.com/influx6/npkg@v0.8.8/nstorage/nmap/nmap.go (about)

     1  package nmap
     2  
     3  import (
     4  	"sync"
     5  	"sync/atomic"
     6  	"time"
     7  
     8  	"github.com/influx6/npkg/nerror"
     9  )
    10  
    11  //**********************************************************************
    12  // AnyMap
    13  //**********************************************************************
    14  
    15  // AnyMap defines an implementation which during initial
    16  // loading stores all key and value pairs.
    17  //
    18  // It provides a safe, concurrently usable implementation with
    19  // blazing read and write speed.
    20  type AnyMap struct {
    21  	Capacity uint
    22  	lock     sync.Mutex
    23  	cache    *atomic.Value
    24  }
    25  
    26  // NewAnyMap returns a new instance of a AnyMap.
    27  func NewAnyMap(cap ...uint) *AnyMap {
    28  	var sm AnyMap
    29  	if len(cap) != 0 {
    30  		sm.Capacity = cap[0]
    31  	}
    32  	return &sm
    33  }
    34  
    35  // Get returns giving value for key.
    36  func (m *AnyMap) Get(k interface{}) (value interface{}) {
    37  	m.GetMany(func(values map[interface{}]interface{}) {
    38  		value = values[k]
    39  	})
    40  	return
    41  }
    42  
    43  // GetMany allows retrieval of many keys from underline map.
    44  //
    45  // WARNING: Never modify the map, ever.
    46  func (m *AnyMap) GetMany(fn func(map[interface{}]interface{})) {
    47  	m.init()
    48  	var cached = m.cache.Load().(map[interface{}]interface{})
    49  	fn(cached)
    50  }
    51  
    52  // Has returns true/false giving value exits for key.
    53  func (m *AnyMap) Has(k string) bool {
    54  	var exists bool
    55  	m.GetMany(func(values map[interface{}]interface{}) {
    56  		_, exists = values[k]
    57  	})
    58  	return exists
    59  }
    60  
    61  // Set adds giving key into underline map.
    62  func (m *AnyMap) Set(k interface{}, value interface{}) {
    63  	m.SetMany(func(values map[interface{}]interface{}) {
    64  		values[k] = value
    65  	})
    66  }
    67  
    68  // SetMany adds giving key into underline map.
    69  func (m *AnyMap) SetMany(fn func(map[interface{}]interface{})) {
    70  	m.init()
    71  
    72  	var cached = m.cache.Load().(map[interface{}]interface{})
    73  	var copied = CopyInterfaceKeyMap(cached)
    74  	fn(copied)
    75  
    76  	m.lock.Lock()
    77  	m.cache.Store(copied)
    78  	m.lock.Unlock()
    79  }
    80  
    81  func (m *AnyMap) init() {
    82  	m.lock.Lock()
    83  	if m.cache != nil {
    84  		m.lock.Unlock()
    85  		return
    86  	}
    87  
    88  	defer m.lock.Unlock()
    89  	if m.Capacity == 0 {
    90  		m.Capacity = 10
    91  	}
    92  
    93  	var newValue atomic.Value
    94  	var store = make(map[interface{}]interface{}, m.Capacity)
    95  	newValue.Store(store)
    96  	m.cache = &newValue
    97  }
    98  
    99  //**********************************************************************
   100  // StringAnyMap
   101  //**********************************************************************
   102  
   103  // StringAnyMap defines an implementation which during initial
   104  // loading stores all key and value pairs.
   105  //
   106  // It provides a safe, concurrently usable implementation with
   107  // blazing read and write speed.
   108  type StringAnyMap struct {
   109  	Capacity uint
   110  	lock     sync.Mutex
   111  	cache    *atomic.Value
   112  }
   113  
   114  // NewStringAnyMap returns a new instance of a StringAnyMap.
   115  func NewStringAnyMap(cap ...uint) *StringAnyMap {
   116  	var sm StringAnyMap
   117  	if len(cap) != 0 {
   118  		sm.Capacity = cap[0]
   119  	}
   120  	return &sm
   121  }
   122  
   123  // Get returns giving value for key.
   124  func (m *StringAnyMap) Get(k string) (value interface{}) {
   125  	m.GetMany(func(values map[string]interface{}) {
   126  		value = values[k]
   127  	})
   128  	return
   129  }
   130  
   131  // GetMany allows retrieval of many keys from underline map.
   132  //
   133  // WARNING: Never modify the map, ever.
   134  func (m *StringAnyMap) GetMany(fn func(map[string]interface{})) {
   135  	m.init()
   136  
   137  	var cached = m.cache.Load().(map[string]interface{})
   138  	fn(cached)
   139  }
   140  
   141  // Has returns true/false giving value exits for key.
   142  func (m *StringAnyMap) Has(k string) bool {
   143  	var exists bool
   144  	m.GetMany(func(values map[string]interface{}) {
   145  		_, exists = values[k]
   146  	})
   147  	return exists
   148  }
   149  
   150  // Set adds giving key into underline map.
   151  func (m *StringAnyMap) Set(k string, value interface{}) {
   152  	m.SetMany(func(values map[string]interface{}) {
   153  		values[k] = value
   154  	})
   155  }
   156  
   157  // SetMany adds giving key into underline map.
   158  func (m *StringAnyMap) SetMany(fn func(map[string]interface{})) {
   159  	m.init()
   160  
   161  	var cached = m.cache.Load().(map[string]interface{})
   162  	var copied = CopyStringKeyMap(cached)
   163  	fn(copied)
   164  
   165  	m.lock.Lock()
   166  	m.cache.Store(copied)
   167  	m.lock.Unlock()
   168  }
   169  
   170  func (m *StringAnyMap) init() {
   171  	m.lock.Lock()
   172  	if m.cache != nil {
   173  		m.lock.Unlock()
   174  		return
   175  	}
   176  
   177  	defer m.lock.Unlock()
   178  	if m.Capacity == 0 {
   179  		m.Capacity = 10
   180  	}
   181  	var store = make(map[string]interface{}, m.Capacity)
   182  
   183  	var newValue atomic.Value
   184  	newValue.Store(store)
   185  	m.cache = &newValue
   186  }
   187  
   188  //**********************************************************************
   189  // StringMap
   190  //**********************************************************************
   191  
   192  // StringMap defines an implementation which during initial
   193  // loading stores all key and value pairs.
   194  //
   195  // It provides a safe, concurrently usable implementation with
   196  // blazing read and write speed.
   197  type StringMap struct {
   198  	Capacity uint
   199  	lock     sync.Mutex
   200  	cache    *atomic.Value
   201  }
   202  
   203  // NewStringMap returns a new instance of a StringMap.
   204  func NewStringMap(cap ...uint) *StringMap {
   205  	var sm StringMap
   206  	if len(cap) != 0 {
   207  		sm.Capacity = cap[0]
   208  	}
   209  	return &sm
   210  }
   211  
   212  // Has returns true/false giving value exits for key.
   213  func (m *StringMap) Has(k string) bool {
   214  	var exists bool
   215  	m.GetMany(func(values map[string]string) {
   216  		_, exists = values[k]
   217  	})
   218  	return exists
   219  }
   220  
   221  // Get returns giving value for key.
   222  func (m *StringMap) Get(k string) (value string) {
   223  	m.GetMany(func(values map[string]string) {
   224  		value = values[k]
   225  	})
   226  	return
   227  }
   228  
   229  // GetMany allows retrieval of many keys from underline map.
   230  //
   231  // WARNING: Never modify the map, ever.
   232  func (m *StringMap) GetMany(fn func(map[string]string)) {
   233  	m.init()
   234  	var cached = m.cache.Load().(map[string]string)
   235  	fn(cached)
   236  }
   237  
   238  // Set adds giving key into underline map.
   239  func (m *StringMap) Set(k string, value string) {
   240  	m.SetMany(func(values map[string]string) {
   241  		values[k] = value
   242  	})
   243  }
   244  
   245  // SetMany adds giving key into underline map.
   246  func (m *StringMap) SetMany(fn func(map[string]string)) {
   247  	m.init()
   248  
   249  	var cached = m.cache.Load().(map[string]string)
   250  	var copied = CopyStringMap(cached)
   251  	fn(copied)
   252  
   253  	m.lock.Lock()
   254  	m.cache.Store(copied)
   255  	m.lock.Unlock()
   256  }
   257  
   258  func (m *StringMap) init() {
   259  	m.lock.Lock()
   260  	if m.cache != nil {
   261  		m.lock.Unlock()
   262  		return
   263  	}
   264  
   265  	defer m.lock.Unlock()
   266  	if m.Capacity == 0 {
   267  		m.Capacity = 10
   268  	}
   269  	var store = make(map[string]string, m.Capacity)
   270  
   271  	var newValue atomic.Value
   272  	newValue.Store(store)
   273  	m.cache = &newValue
   274  }
   275  
   276  //**********************************************************************
   277  // ByteMap
   278  //**********************************************************************
   279  
   280  // ByteMap defines an implementation which during initial
   281  // loading stores all key and value pairs.
   282  //
   283  // It provides a safe, concurrently usable implementation with
   284  // blazing read and write speed.
   285  type ByteMap struct {
   286  	Capacity uint
   287  	lock     sync.Mutex
   288  	cache    *atomic.Value
   289  }
   290  
   291  // NewByteMap returns a new instance of a ByteMap.
   292  func NewByteMap(cap ...uint) *ByteMap {
   293  	var sm ByteMap
   294  	if len(cap) != 0 {
   295  		sm.Capacity = cap[0]
   296  	}
   297  	return &sm
   298  }
   299  
   300  // Has returns true/false giving value exits for key.
   301  func (m *ByteMap) Has(k string) bool {
   302  	var exists bool
   303  	m.GetMany(func(values map[string][]byte) {
   304  		_, exists = values[k]
   305  	})
   306  	return exists
   307  }
   308  
   309  // Get returns giving value for key.
   310  //
   311  // Get makes a copy of the content of the key
   312  // returning that, which causes a single allocation,
   313  // use GetMany to access the content of the key directly
   314  // without any copy, but ensure to copy the content as
   315  // necessary to avoid corruption of value.
   316  func (m *ByteMap) Get(k string) (value []byte) {
   317  	m.GetMany(func(values map[string][]byte) {
   318  		if nvalue, ok := values[k]; ok {
   319  			var content = make([]byte, len(nvalue))
   320  			copy(content, nvalue)
   321  			value = content
   322  		}
   323  	})
   324  	return
   325  }
   326  
   327  // GetMany allows retrieval of many keys from underline map.
   328  //
   329  // Get makes a copy of the content of the key
   330  // returning that, which causes a single allocation,
   331  // use GetMany to access the content of the key directly
   332  // without any copy, but ensure to copy the content as
   333  // necessary to avoid corruption of value.
   334  //
   335  // WARNING: Never modify the map, ever.
   336  func (m *ByteMap) GetMany(fn func(map[string][]byte)) {
   337  	m.init()
   338  	var cached = m.cache.Load().(map[string][]byte)
   339  	fn(cached)
   340  }
   341  
   342  // Set adds giving key into underline map.
   343  func (m *ByteMap) Set(k string, value []byte) {
   344  	m.SetMany(func(values map[string][]byte) {
   345  		var content = make([]byte, len(value))
   346  		copy(content, value)
   347  		values[k] = content
   348  	})
   349  }
   350  
   351  // SetMany adds giving key into underline map.
   352  func (m *ByteMap) SetMany(fn func(map[string][]byte)) {
   353  	m.init()
   354  
   355  	var cached = m.cache.Load().(map[string][]byte)
   356  	var copied = CopyStringBytesMap(cached)
   357  	fn(copied)
   358  
   359  	m.lock.Lock()
   360  	m.cache.Store(copied)
   361  	m.lock.Unlock()
   362  }
   363  
   364  func (m *ByteMap) Count() int64 {
   365  	m.init()
   366  	var cached = m.cache.Load().(map[string][]byte)
   367  	return int64(len(cached))
   368  }
   369  
   370  func (m *ByteMap) init() {
   371  	m.lock.Lock()
   372  	if m.cache != nil {
   373  		m.lock.Unlock()
   374  		return
   375  	}
   376  
   377  	defer m.lock.Unlock()
   378  	if m.Capacity == 0 {
   379  		m.Capacity = 10
   380  	}
   381  	var store = make(map[string][]byte, m.Capacity)
   382  
   383  	var newValue atomic.Value
   384  	newValue.Store(store)
   385  	m.cache = &newValue
   386  }
   387  
   388  //**********************************************************************
   389  // ExpiringByteMap
   390  //**********************************************************************
   391  var zeroTime = time.Time{}
   392  
   393  // ExpiringValue defines a type which holds a giving byte value
   394  // string, it has if attached a possible expiring value, which would
   395  // make it unaccessible once expired.
   396  type ExpiringValue struct {
   397  	Value []byte
   398  	when  time.Time
   399  }
   400  
   401  // Elapsed returns the current duration left for expiring.
   402  //
   403  // A positive number means there is still time and a negative
   404  // number means it has expired. But zero means no expiration.
   405  func (ne *ExpiringValue) Elapsed() time.Duration {
   406  	if ne.when.IsZero() {
   407  		return 0
   408  	}
   409  	var current = time.Now()
   410  	if current.Before(ne.when) {
   411  		return ne.when.Sub(current)
   412  	}
   413  	return current.Sub(ne.when)
   414  }
   415  
   416  // Expired returns true/false if giving value is expired.
   417  func (ne *ExpiringValue) Expired() bool {
   418  	if !ne.when.IsZero() {
   419  		var current = time.Now()
   420  		if current.After(ne.when) {
   421  			return true
   422  		}
   423  	}
   424  	return false
   425  }
   426  
   427  // NewExpiringValue returns a new instance of a ExpiringValue.
   428  func NewExpiringValue(value []byte, ttl time.Duration) ExpiringValue {
   429  	var exr ExpiringValue
   430  	exr.Value = value
   431  	if ttl > 0 {
   432  		exr.when = time.Now().Add(ttl)
   433  	}
   434  	return exr
   435  }
   436  
   437  // ExpiringByteMap defines an implementation which during initial
   438  // loading stores all key and value pairs.
   439  //
   440  // It provides a safe, concurrently usable implementation with
   441  // blazing read and write speed.
   442  type ExpiringByteMap struct {
   443  	Capacity uint
   444  	lock     sync.Mutex
   445  	cache    *atomic.Value
   446  }
   447  
   448  // NewExpiringByteMap returns a new instance of a ExpiringByteMap.
   449  func NewExpiringByteMap(cap ...uint) *ExpiringByteMap {
   450  	var sm ExpiringByteMap
   451  	if len(cap) != 0 {
   452  		sm.Capacity = cap[0]
   453  	}
   454  	return &sm
   455  }
   456  
   457  // Has returns true/false giving value exits for key.
   458  func (m *ExpiringByteMap) Has(k string) bool {
   459  	var exists bool
   460  	m.GetMany(func(values map[string]ExpiringValue) {
   461  		_, exists = values[k]
   462  	})
   463  	return exists
   464  }
   465  
   466  // Get returns giving value for key.
   467  //
   468  // Get makes a copy of the content of the key
   469  // returning that, which causes a single allocation,
   470  // use GetMany to access the content of the key directly
   471  // without any copy, but ensure to copy the content as
   472  // necessary to avoid corruption of value.
   473  func (m *ExpiringByteMap) Get(k string) (value []byte) {
   474  	m.GetMany(func(values map[string]ExpiringValue) {
   475  		if nvalue, ok := values[k]; ok {
   476  			if nvalue.Expired() {
   477  				return
   478  			}
   479  
   480  			var content = make([]byte, len(nvalue.Value))
   481  			copy(content, nvalue.Value)
   482  			value = content
   483  		}
   484  	})
   485  	return
   486  }
   487  
   488  func (m *ExpiringByteMap) GetAnyKeys(keys ...string) (values [][]byte, err error) {
   489  	values = make([][]byte, len(keys))
   490  	m.GetMany(func(data map[string]ExpiringValue) {
   491  		for index, k := range keys {
   492  			if nvalue, ok := data[k]; ok {
   493  				if nvalue.Expired() {
   494  					values[index] = nil
   495  					continue
   496  				}
   497  
   498  				var content = make([]byte, len(nvalue.Value))
   499  				copy(content, nvalue.Value)
   500  				values[index] = content
   501  				continue
   502  			}
   503  			values[index] = nil
   504  		}
   505  	})
   506  	return
   507  }
   508  
   509  func (m *ExpiringByteMap) GetAllKeys(keys ...string) (values [][]byte, err error) {
   510  	values = make([][]byte, len(keys))
   511  	m.GetMany(func(data map[string]ExpiringValue) {
   512  		for index, k := range keys {
   513  			if nvalue, ok := data[k]; ok {
   514  				if nvalue.Expired() {
   515  					err = nerror.New("key %q has expired", k)
   516  					return
   517  				}
   518  
   519  				var content = make([]byte, len(nvalue.Value))
   520  				copy(content, nvalue.Value)
   521  				values[index] = content
   522  				continue
   523  			}
   524  			err = nerror.New("not found")
   525  			break
   526  		}
   527  	})
   528  	return
   529  }
   530  
   531  // TTL returns the current remaining time before giving key expires.
   532  func (m *ExpiringByteMap) TTL(k string) (value time.Duration) {
   533  	m.GetMany(func(values map[string]ExpiringValue) {
   534  		if nvalue, ok := values[k]; ok {
   535  			value = nvalue.Elapsed()
   536  		}
   537  	})
   538  	return
   539  }
   540  
   541  // GetManyErr allows retrieval of many keys from underline map.
   542  //
   543  // Get makes a copy of the content of the key
   544  // returning that, which causes a single allocation,
   545  // use GetMany to access the content of the key directly
   546  // without any copy, but ensure to copy the content as
   547  // necessary to avoid corruption of value.
   548  //
   549  // You are expected to respect the expiry values of a ExpiringValue
   550  // and ignore any that as expired as a cleanup will be done later.
   551  //
   552  // WARNING: Never modify the map, ever.
   553  func (m *ExpiringByteMap) GetManyErr(fn func(map[string]ExpiringValue) error) error {
   554  	m.init()
   555  	var cached = m.cache.Load().(map[string]ExpiringValue)
   556  	return fn(cached)
   557  }
   558  
   559  // GetMany allows retrieval of many keys from underline map.
   560  //
   561  // Get makes a copy of the content of the key
   562  // returning that, which causes a single allocation,
   563  // use GetMany to access the content of the key directly
   564  // without any copy, but ensure to copy the content as
   565  // necessary to avoid corruption of value.
   566  //
   567  // You are expected to respect the expiry values of a ExpiringValue
   568  // and ignore any that as expired as a cleanup will be done later.
   569  //
   570  // WARNING: Never modify the map, ever.
   571  func (m *ExpiringByteMap) GetMany(fn func(map[string]ExpiringValue)) {
   572  	m.init()
   573  	var cached = m.cache.Load().(map[string]ExpiringValue)
   574  	fn(cached)
   575  }
   576  
   577  // Set adds giving key into underline map.
   578  //
   579  // if expiration is zero then giving value expiration will not be reset but left
   580  // as is.
   581  //
   582  // Set automatically cleans up the map of expired keys.
   583  func (m *ExpiringByteMap) Set(k string, value []byte, expire time.Duration) {
   584  	m.SetMany(func(values map[string]ExpiringValue) {
   585  		if nval, ok := values[k]; ok {
   586  			nval.Value = value
   587  			if expire > 0 {
   588  				nval.when = time.Now().Add(expire)
   589  			}
   590  			values[k] = nval
   591  			return
   592  		}
   593  		values[k] = NewExpiringValue(value, expire)
   594  	})
   595  }
   596  
   597  // ExtendTTL extends giving key value expiration by provided value.
   598  //
   599  // A expiration value of zero means to persist the giving key.
   600  func (m *ExpiringByteMap) ExtendTTL(k string, expire time.Duration) {
   601  	m.SetMany(func(values map[string]ExpiringValue) {
   602  		if nval, ok := values[k]; ok {
   603  			if expire != 0 {
   604  				if nval.when.IsZero() {
   605  					nval.when = time.Now().Add(expire)
   606  				} else {
   607  					nval.when = nval.when.Add(expire)
   608  				}
   609  			} else {
   610  				nval.when = zeroTime
   611  			}
   612  			values[k] = nval
   613  			return
   614  		}
   615  	})
   616  }
   617  
   618  // ResetTTL resets the expiration of giving key, persisting if duration
   619  // provided is zero.
   620  func (m *ExpiringByteMap) ResetTTL(k string, expire time.Duration) {
   621  	m.SetMany(func(values map[string]ExpiringValue) {
   622  		if nval, ok := values[k]; ok {
   623  			if expire != 0 {
   624  				nval.when = time.Now().Add(expire)
   625  			} else {
   626  				nval.when = zeroTime
   627  			}
   628  			values[k] = nval
   629  			return
   630  		}
   631  	})
   632  }
   633  
   634  func (m *ExpiringByteMap) Count() int64 {
   635  	m.init()
   636  	var cached = m.cache.Load().(map[string]ExpiringValue)
   637  	return int64(len(cached))
   638  }
   639  
   640  func (m *ExpiringByteMap) Reset() {
   641  	m.init()
   642  
   643  	var newCache = map[string]ExpiringValue{}
   644  	m.lock.Lock()
   645  	m.cache.Store(newCache)
   646  	m.lock.Unlock()
   647  }
   648  
   649  // SetMany adds giving key into underline map.
   650  func (m *ExpiringByteMap) SetMany(fn func(map[string]ExpiringValue)) {
   651  	m.init()
   652  
   653  	var cached = m.cache.Load().(map[string]ExpiringValue)
   654  	var copied = CopyExpiringBytesMap(cached)
   655  	fn(copied)
   656  
   657  	m.lock.Lock()
   658  	m.cache.Store(copied)
   659  	m.lock.Unlock()
   660  }
   661  
   662  func (m *ExpiringByteMap) init() {
   663  	m.lock.Lock()
   664  	if m.cache != nil {
   665  		m.lock.Unlock()
   666  		return
   667  	}
   668  
   669  	defer m.lock.Unlock()
   670  	if m.Capacity == 0 {
   671  		m.Capacity = 10
   672  	}
   673  	var store = make(map[string]ExpiringValue, m.Capacity)
   674  
   675  	var newValue atomic.Value
   676  	newValue.Store(store)
   677  	m.cache = &newValue
   678  }