github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/http_cache.go (about) 1 package ravendb 2 3 import ( 4 //"fmt" 5 6 "math" 7 "sync" 8 "sync/atomic" 9 "time" 10 ) 11 12 // equivalent of com.google.common.cache.Cache, specialized for String -> HttpCacheItem mapping 13 // TODO: match semantics 14 type genericCache struct { 15 softValues bool 16 maximumWeight int 17 weighter func(string, *httpCacheItem) int 18 19 data *sync.Map 20 } 21 22 func (c *genericCache) size() int { 23 // this is probably only ever going to be called from tests 24 // fine to do O(N) work here 25 length := 0 26 c.data.Range(func(_, _ interface{}) bool { 27 length++ 28 return true 29 }) 30 return length 31 } 32 33 func (c *genericCache) invalidateAll() { 34 c.data = &sync.Map{} 35 } 36 37 func (c *genericCache) getIfPresent(uri string) *httpCacheItem { 38 item, found := c.data.Load(uri) 39 if !found { 40 return nil 41 } 42 return item.(*httpCacheItem) 43 } 44 45 func (c *genericCache) put(uri string, i *httpCacheItem) { 46 //fmt.Printf("genericCache.put(): url: %s, changeVector: %s, len(result): %d\n", uri, *i.changeVector, len(i.payload)) 47 48 // TODO: probably implement cache eviction 49 c.data.Store(uri, i) 50 } 51 52 type httpCache struct { 53 items *genericCache 54 generation int32 // atomic 55 } 56 57 func (c *httpCache) incGeneration() { 58 atomic.AddInt32(&c.generation, 1) 59 } 60 61 func (c *httpCache) getGeneration() int { 62 v := atomic.LoadInt32(&c.generation) 63 return int(v) 64 } 65 66 func newHttpCache(size int) *httpCache { 67 if size == 0 { 68 size = 1 * 1024 * 1024 // TODO: check what is default size of com.google.common.cache.Cache is 69 } 70 cache := &genericCache{ 71 softValues: true, 72 maximumWeight: size, 73 weighter: func(k string, v *httpCacheItem) int { 74 return len(v.payload) + 20 75 }, 76 data: &sync.Map{ }, 77 } 78 return &httpCache{ 79 items: cache, 80 } 81 } 82 83 func (c *httpCache) GetNumberOfItems() int { 84 return c.items.size() 85 } 86 87 func (c *httpCache) close() { 88 c.items.invalidateAll() 89 c.items = nil 90 } 91 92 func (c *httpCache) set(url string, changeVector *string, result []byte) { 93 httpCacheItem := newHttpCacheItem() 94 httpCacheItem.changeVector = changeVector 95 httpCacheItem.payload = result 96 httpCacheItem.cache = c 97 httpCacheItem.generation = c.getGeneration() 98 c.items.put(url, httpCacheItem) 99 } 100 101 // returns cacheItem, changeVector and response 102 func (c *httpCache) get(url string) (*releaseCacheItem, *string, []byte) { 103 item := c.items.getIfPresent(url) 104 if item != nil { 105 //fmt.Printf("HttpCache.get(): found url: %s, changeVector: %s, len(payload): %d\n", url, *item.changeVector, len(item.payload)) 106 return newReleaseCacheItem(item), item.changeVector, item.payload 107 } 108 109 //fmt.Printf("HttpCache.get(): didn't find url: %s\n", url) 110 return newReleaseCacheItem(nil), nil, nil 111 } 112 113 func (c *httpCache) setNotFound(url string) { 114 //fmt.Printf("HttpCache.setNotFound(): url: %s\n", url) 115 httpCacheItem := newHttpCacheItem() 116 s := "404 response" 117 httpCacheItem.changeVector = &s 118 httpCacheItem.cache = c 119 httpCacheItem.generation = c.getGeneration() 120 121 c.items.put(url, httpCacheItem) 122 } 123 124 type releaseCacheItem struct { 125 item *httpCacheItem 126 } 127 128 func newReleaseCacheItem(item *httpCacheItem) *releaseCacheItem { 129 return &releaseCacheItem{ 130 item: item, 131 } 132 } 133 134 func (i *releaseCacheItem) notModified() { 135 if i.item != nil { 136 i.item.lastServerUpdate = time.Now() 137 } 138 } 139 140 func (i *releaseCacheItem) getAge() time.Duration { 141 if i.item == nil { 142 return time.Duration(math.MaxInt64) 143 } 144 return time.Since(i.item.lastServerUpdate) 145 } 146 147 func (i *releaseCacheItem) getMightHaveBeenModified() bool { 148 currGen := i.item.generation 149 itemGen := i.item.cache.getGeneration() 150 return currGen != itemGen 151 } 152 153 func (i *releaseCacheItem) close() { 154 // no-op 155 }