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 }