github.com/gogf/gf@v1.16.9/os/gcache/gcache_adapter_memory_lru.go (about)

     1  // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
     2  //
     3  // This Source Code Form is subject to the terms of the MIT License.
     4  // If a copy of the MIT was not distributed with this file,
     5  // You can obtain one at https://github.com/gogf/gf.
     6  
     7  package gcache
     8  
     9  import (
    10  	"time"
    11  
    12  	"github.com/gogf/gf/container/glist"
    13  	"github.com/gogf/gf/container/gmap"
    14  	"github.com/gogf/gf/container/gtype"
    15  	"github.com/gogf/gf/os/gtimer"
    16  )
    17  
    18  // LRU cache object.
    19  // It uses list.List from stdlib for its underlying doubly linked list.
    20  type adapterMemoryLru struct {
    21  	cache   *adapterMemory // Parent cache object.
    22  	data    *gmap.Map      // Key mapping to the item of the list.
    23  	list    *glist.List    // Key list.
    24  	rawList *glist.List    // History for key adding.
    25  	closed  *gtype.Bool    // Closed or not.
    26  }
    27  
    28  // newMemCacheLru creates and returns a new LRU object.
    29  func newMemCacheLru(cache *adapterMemory) *adapterMemoryLru {
    30  	lru := &adapterMemoryLru{
    31  		cache:   cache,
    32  		data:    gmap.New(true),
    33  		list:    glist.New(true),
    34  		rawList: glist.New(true),
    35  		closed:  gtype.NewBool(),
    36  	}
    37  	gtimer.AddSingleton(time.Second, lru.SyncAndClear)
    38  	return lru
    39  }
    40  
    41  // Close closes the LRU object.
    42  func (lru *adapterMemoryLru) Close() {
    43  	lru.closed.Set(true)
    44  }
    45  
    46  // Remove deletes the `key` FROM `lru`.
    47  func (lru *adapterMemoryLru) Remove(key interface{}) {
    48  	if v := lru.data.Get(key); v != nil {
    49  		lru.data.Remove(key)
    50  		lru.list.Remove(v.(*glist.Element))
    51  	}
    52  }
    53  
    54  // Size returns the size of `lru`.
    55  func (lru *adapterMemoryLru) Size() int {
    56  	return lru.data.Size()
    57  }
    58  
    59  // Push pushes `key` to the tail of `lru`.
    60  func (lru *adapterMemoryLru) Push(key interface{}) {
    61  	lru.rawList.PushBack(key)
    62  }
    63  
    64  // Pop deletes and returns the key from tail of `lru`.
    65  func (lru *adapterMemoryLru) Pop() interface{} {
    66  	if v := lru.list.PopBack(); v != nil {
    67  		lru.data.Remove(v)
    68  		return v
    69  	}
    70  	return nil
    71  }
    72  
    73  // Print is used for test only.
    74  //func (lru *adapterMemoryLru) Print() {
    75  //    for _, v := range lru.list.FrontAll() {
    76  //        fmt.Printf("%v ", v)
    77  //    }
    78  //    fmt.Println()
    79  //}
    80  
    81  // SyncAndClear synchronizes the keys from `rawList` to `list` and `data`
    82  // using Least Recently Used algorithm.
    83  func (lru *adapterMemoryLru) SyncAndClear() {
    84  	if lru.closed.Val() {
    85  		gtimer.Exit()
    86  		return
    87  	}
    88  	// Data synchronization.
    89  	for {
    90  		if v := lru.rawList.PopFront(); v != nil {
    91  			// Deleting the key from list.
    92  			if v := lru.data.Get(v); v != nil {
    93  				lru.list.Remove(v.(*glist.Element))
    94  			}
    95  			// Pushing key to the head of the list
    96  			// and setting its list item to hash table for quick indexing.
    97  			lru.data.Set(v, lru.list.PushFront(v))
    98  		} else {
    99  			break
   100  		}
   101  	}
   102  	// Data cleaning up.
   103  	for i := lru.Size() - lru.cache.cap; i > 0; i-- {
   104  		if s := lru.Pop(); s != nil {
   105  			lru.cache.clearByKey(s, true)
   106  		}
   107  	}
   108  }