github.com/ergo-services/ergo@v1.999.224/etf/cache.go (about)

     1  package etf
     2  
     3  import (
     4  	"sync"
     5  )
     6  
     7  const (
     8  	maxCacheItems = int16(2048)
     9  )
    10  
    11  type AtomCache struct {
    12  	In  *AtomCacheIn
    13  	Out *AtomCacheOut
    14  }
    15  
    16  type AtomCacheIn struct {
    17  	Atoms [maxCacheItems]*Atom
    18  }
    19  
    20  // AtomCache
    21  type AtomCacheOut struct {
    22  	sync.RWMutex
    23  	cacheMap  map[Atom]int16
    24  	id        int16
    25  	cacheList [maxCacheItems]Atom
    26  }
    27  
    28  // CacheItem
    29  type CacheItem struct {
    30  	ID      int16
    31  	Encoded bool
    32  	Name    Atom
    33  }
    34  
    35  var (
    36  	encodingAtomCachePool = &sync.Pool{
    37  		New: func() interface{} {
    38  			l := &EncodingAtomCache{
    39  				L:     make([]CacheItem, 0, 255),
    40  				added: make(map[Atom]uint8),
    41  			}
    42  			l.original = l.L
    43  			return l
    44  		},
    45  	}
    46  )
    47  
    48  // NewAtomCache
    49  func NewAtomCache() AtomCache {
    50  	return AtomCache{
    51  		In: &AtomCacheIn{},
    52  		Out: &AtomCacheOut{
    53  			cacheMap: make(map[Atom]int16),
    54  			id:       -1,
    55  		},
    56  	}
    57  }
    58  
    59  type AtomMapping struct {
    60  	MutexIn  sync.RWMutex
    61  	In       map[Atom]Atom
    62  	MutexOut sync.RWMutex
    63  	Out      map[Atom]Atom
    64  }
    65  
    66  // NewAtomMapping
    67  func NewAtomMapping() *AtomMapping {
    68  	return &AtomMapping{
    69  		In:  make(map[Atom]Atom),
    70  		Out: make(map[Atom]Atom),
    71  	}
    72  }
    73  
    74  // Append
    75  func (a *AtomCacheOut) Append(atom Atom) (int16, bool) {
    76  	a.Lock()
    77  	defer a.Unlock()
    78  
    79  	if a.id > maxCacheItems-2 {
    80  		return 0, false
    81  	}
    82  
    83  	if id, exist := a.cacheMap[atom]; exist {
    84  		return id, false
    85  	}
    86  
    87  	a.id++
    88  	a.cacheList[a.id] = atom
    89  	a.cacheMap[atom] = a.id
    90  
    91  	return a.id, true
    92  }
    93  
    94  // LastID
    95  func (a *AtomCacheOut) LastAdded() (Atom, int16) {
    96  	a.RLock()
    97  	defer a.RUnlock()
    98  	l := len(a.cacheList)
    99  	if l == 0 {
   100  		return "", -1
   101  	}
   102  	return a.cacheList[l-1], int16(l - 1)
   103  }
   104  
   105  // ListSince
   106  func (a *AtomCacheOut) ListSince(id int16) []Atom {
   107  	if id < 0 {
   108  		id = 0
   109  	}
   110  	if int(id) > len(a.cacheList)-1 {
   111  		return nil
   112  	}
   113  	return a.cacheList[id:]
   114  }
   115  
   116  // EncodingAtomCache
   117  type EncodingAtomCache struct {
   118  	L           []CacheItem
   119  	original    []CacheItem
   120  	added       map[Atom]uint8
   121  	HasLongAtom bool
   122  }
   123  
   124  // TakeEncodingAtomCache
   125  func TakeEncodingAtomCache() *EncodingAtomCache {
   126  	return encodingAtomCachePool.Get().(*EncodingAtomCache)
   127  }
   128  
   129  // ReleaseEncodingAtomCache
   130  func ReleaseEncodingAtomCache(l *EncodingAtomCache) {
   131  	l.L = l.original[:0]
   132  	if len(l.added) > 0 {
   133  		for k, _ := range l.added {
   134  			delete(l.added, k)
   135  		}
   136  	}
   137  	encodingAtomCachePool.Put(l)
   138  }
   139  
   140  // Reset
   141  func (l *EncodingAtomCache) Reset() {
   142  	l.L = l.original[:0]
   143  	l.HasLongAtom = false
   144  	if len(l.added) > 0 {
   145  		for k, _ := range l.added {
   146  			delete(l.added, k)
   147  		}
   148  	}
   149  }
   150  
   151  // Append
   152  func (l *EncodingAtomCache) Append(a CacheItem) uint8 {
   153  	id, added := l.added[a.Name]
   154  	if added {
   155  		return id
   156  	}
   157  
   158  	l.L = append(l.L, a)
   159  	if !a.Encoded && len(a.Name) > 255 {
   160  		l.HasLongAtom = true
   161  	}
   162  	id = uint8(len(l.L) - 1)
   163  	l.added[a.Name] = id
   164  	return id
   165  }
   166  
   167  // Delete
   168  func (l *EncodingAtomCache) Delete(atom Atom) {
   169  	// clean up in order to get rid of map reallocation which is pretty expensive
   170  	delete(l.added, atom)
   171  }
   172  
   173  // Len
   174  func (l *EncodingAtomCache) Len() int {
   175  	return len(l.L)
   176  }