github.com/zhongdalu/gf@v1.0.0/g/os/gcache/gcache_mem_cache_lru.go (about)

     1  // Copyright 2018 gf Author(https://github.com/zhongdalu/gf). 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/zhongdalu/gf.
     6  
     7  package gcache
     8  
     9  import (
    10  	"github.com/zhongdalu/gf/g/container/glist"
    11  	"github.com/zhongdalu/gf/g/container/gmap"
    12  	"github.com/zhongdalu/gf/g/container/gtype"
    13  	"github.com/zhongdalu/gf/g/os/gtimer"
    14  	"time"
    15  )
    16  
    17  // LRU cache object.
    18  // It uses list.List from stdlib for its underlying doubly linked list.
    19  type memCacheLru struct {
    20  	cache   *memCache   // Parent cache object.
    21  	data    *gmap.Map   // Key mapping to the item of the list.
    22  	list    *glist.List // Key list.
    23  	rawList *glist.List // History for key adding.
    24  	closed  *gtype.Bool // Closed or not.
    25  }
    26  
    27  // newMemCacheLru creates and returns a new LRU object.
    28  func newMemCacheLru(cache *memCache) *memCacheLru {
    29  	lru := &memCacheLru{
    30  		cache:   cache,
    31  		data:    gmap.New(),
    32  		list:    glist.New(),
    33  		rawList: glist.New(),
    34  		closed:  gtype.NewBool(),
    35  	}
    36  	gtimer.AddSingleton(time.Second, lru.SyncAndClear)
    37  	return lru
    38  }
    39  
    40  // Close closes the LRU object.
    41  func (lru *memCacheLru) Close() {
    42  	lru.closed.Set(true)
    43  }
    44  
    45  // Remove deletes the <key> FROM <lru>.
    46  func (lru *memCacheLru) 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 *memCacheLru) Size() int {
    55  	return lru.data.Size()
    56  }
    57  
    58  // Push pushes <key> to the tail of <lru>.
    59  func (lru *memCacheLru) Push(key interface{}) {
    60  	lru.rawList.PushBack(key)
    61  }
    62  
    63  // Pop deletes and returns the key from tail of <lru>.
    64  func (lru *memCacheLru) 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  // Print is used for test only.
    73  //func (lru *memCacheLru) Print() {
    74  //    for _, v := range lru.list.FrontAll() {
    75  //        fmt.Printf("%v ", v)
    76  //    }
    77  //    fmt.Println()
    78  //}
    79  
    80  // SyncAndClear synchronizes the keys from <rawList> to <list> and <data>
    81  // using Least Recently Used algorithm.
    82  func (lru *memCacheLru) SyncAndClear() {
    83  	if lru.closed.Val() {
    84  		gtimer.Exit()
    85  		return
    86  	}
    87  	// Data synchronization.
    88  	for {
    89  		if v := lru.rawList.PopFront(); v != nil {
    90  			// Deleting the key from list.
    91  			if v := lru.data.Get(v); v != nil {
    92  				lru.list.Remove(v.(*glist.Element))
    93  			}
    94  			// Pushing key to the head of the list
    95  			// and setting its list item to hash table for quick indexing.
    96  			lru.data.Set(v, lru.list.PushFront(v))
    97  		} else {
    98  			break
    99  		}
   100  	}
   101  	// Data cleaning up.
   102  	for i := lru.Size() - lru.cache.cap; i > 0; i-- {
   103  		if s := lru.Pop(); s != nil {
   104  			lru.cache.clearByKey(s, true)
   105  		}
   106  	}
   107  }