github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/fasthttprouter_cache.go (about)

     1  // Copyright 2017-present Kirill Danshin and Gramework contributors
     2  // Copyright 2019-present Highload LTD (UK CN: 11893420)
     3  //
     4  // Licensed under the Apache License, Version 2.0 (the "License");
     5  // you may not use this file except in compliance with the License.
     6  // You may obtain a copy of the License at
     7  //
     8  //     http://www.apache.org/licenses/LICENSE-2.0
     9  //
    10  
    11  package gramework
    12  
    13  import (
    14  	"runtime"
    15  	"sync"
    16  	"time"
    17  )
    18  
    19  type (
    20  	cache struct {
    21  		v  map[string]*msc
    22  		mu sync.RWMutex
    23  	}
    24  
    25  	// method-specific cache
    26  	msc struct {
    27  		v  map[string]*cacheRecord
    28  		mu sync.RWMutex
    29  	}
    30  
    31  	cacheRecord struct {
    32  		n              *node
    33  		tsr            bool
    34  		values         map[string]string
    35  		lastAccessTime int64
    36  	}
    37  )
    38  
    39  const cacheRecordTTLDelta = 20 * 1000000000
    40  
    41  func (c *cache) getOrInitMSC(method string) *msc {
    42  	c.mu.Lock()
    43  	if v, ok := c.v[method]; ok {
    44  		c.mu.Unlock()
    45  		return v
    46  	}
    47  	ms := &msc{
    48  		v: make(map[string]*cacheRecord),
    49  	}
    50  	c.v[method] = ms
    51  	c.mu.Unlock()
    52  	return ms
    53  }
    54  
    55  func (c *cache) getMSC(method string) *msc {
    56  	c.mu.RLock()
    57  	if v, ok := c.v[method]; ok {
    58  		c.mu.RUnlock()
    59  		return v
    60  	}
    61  	c.mu.RUnlock()
    62  	return nil
    63  }
    64  
    65  func (c *cache) Put(path string, n *node, tsr bool, method string) {
    66  	msc := c.getOrInitMSC(method)
    67  	msc.mu.Lock()
    68  	msc.v[path] = &cacheRecord{
    69  		n:              n,
    70  		tsr:            tsr,
    71  		lastAccessTime: Nanotime(),
    72  	}
    73  	msc.mu.Unlock()
    74  }
    75  
    76  func (c *cache) PutWild(path string, n *node, tsr bool, values map[string]string, method string) {
    77  	msc := c.getOrInitMSC(method)
    78  	msc.mu.Lock()
    79  	msc.v[path] = &cacheRecord{
    80  		n:              n,
    81  		tsr:            tsr,
    82  		values:         values,
    83  		lastAccessTime: Nanotime(),
    84  	}
    85  	msc.mu.Unlock()
    86  }
    87  
    88  func (c *cache) Get(path string, method string) (n *cacheRecord, ok bool) {
    89  	msc := c.getMSC(method)
    90  	if msc == nil {
    91  		return nil, false
    92  	}
    93  	msc.mu.RLock()
    94  	n, ok = msc.v[path]
    95  	if ok {
    96  		n.lastAccessTime = Nanotime()
    97  	}
    98  	msc.mu.RUnlock()
    99  	return
   100  }
   101  
   102  func (c *cache) maintain() {
   103  	for {
   104  		runtime.Gosched()
   105  		time.Sleep(30 * time.Second)
   106  		skipIter := true
   107  		c.mu.RLock()
   108  		for _, v := range c.v {
   109  			v.mu.RLock()
   110  			mscLen := len(v.v)
   111  			v.mu.RUnlock()
   112  			if mscLen > 256 {
   113  				skipIter = false
   114  				break
   115  			}
   116  		}
   117  		if skipIter {
   118  			c.mu.RUnlock()
   119  			continue
   120  		}
   121  		for _, msc := range c.v {
   122  			if len(msc.v) <= 256 {
   123  				continue
   124  			}
   125  			msc.mu.Lock()
   126  			for path := range msc.v {
   127  				if Nanotime()-cacheRecordTTLDelta > msc.v[path].lastAccessTime {
   128  					msc.v[path].n.hits = 0
   129  					delete(c.v, path)
   130  				}
   131  			}
   132  			msc.mu.Unlock()
   133  		}
   134  		c.mu.RUnlock()
   135  	}
   136  }