github.com/gogf/gf/v2@v2.7.4/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  	"context"
    11  
    12  	"github.com/gogf/gf/v2/container/glist"
    13  	"github.com/gogf/gf/v2/container/gmap"
    14  	"github.com/gogf/gf/v2/container/gtype"
    15  	"github.com/gogf/gf/v2/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  	return lru
    38  }
    39  
    40  // Close closes the LRU object.
    41  func (lru *adapterMemoryLru) Close() {
    42  	lru.closed.Set(true)
    43  }
    44  
    45  // Remove deletes the `key` FROM `lru`.
    46  func (lru *adapterMemoryLru) Remove(key interface{}) {
    47  	if v := lru.data.Get(key); v != nil {
    48  		lru.data.Remove(key)
    49  		lru.list.Remove(v.(*glist.Element))
    50  	}
    51  }
    52  
    53  // Size returns the size of `lru`.
    54  func (lru *adapterMemoryLru) Size() int {
    55  	return lru.data.Size()
    56  }
    57  
    58  // Push pushes `key` to the tail of `lru`.
    59  func (lru *adapterMemoryLru) Push(key interface{}) {
    60  	lru.rawList.PushBack(key)
    61  }
    62  
    63  // Pop deletes and returns the key from tail of `lru`.
    64  func (lru *adapterMemoryLru) Pop() interface{} {
    65  	if v := lru.list.PopBack(); v != nil {
    66  		lru.data.Remove(v)
    67  		return v
    68  	}
    69  	return nil
    70  }
    71  
    72  // SyncAndClear synchronizes the keys from `rawList` to `list` and `data`
    73  // using Least Recently Used algorithm.
    74  func (lru *adapterMemoryLru) SyncAndClear(ctx context.Context) {
    75  	if lru.closed.Val() {
    76  		gtimer.Exit()
    77  		return
    78  	}
    79  	// Data synchronization.
    80  	var alreadyExistItem interface{}
    81  	for {
    82  		if rawListItem := lru.rawList.PopFront(); rawListItem != nil {
    83  			// Deleting the key from list.
    84  			if alreadyExistItem = lru.data.Get(rawListItem); alreadyExistItem != nil {
    85  				lru.list.Remove(alreadyExistItem.(*glist.Element))
    86  			}
    87  			// Pushing key to the head of the list
    88  			// and setting its list item to hash table for quick indexing.
    89  			lru.data.Set(rawListItem, lru.list.PushFront(rawListItem))
    90  		} else {
    91  			break
    92  		}
    93  	}
    94  	// Data cleaning up.
    95  	for clearLength := lru.Size() - lru.cache.cap; clearLength > 0; clearLength-- {
    96  		if topKey := lru.Pop(); topKey != nil {
    97  			lru.cache.clearByKey(topKey, true)
    98  		}
    99  	}
   100  }