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  }