cache.go 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. package cache
  2. import (
  3. "encoding/gob"
  4. "fmt"
  5. "io"
  6. "os"
  7. "runtime"
  8. "sync"
  9. "time"
  10. )
  11. type Item struct {
  12. Object interface{}
  13. Expiration int64
  14. }
  15. // Returns true if the item has expired.
  16. func (item Item) Expired() bool {
  17. if item.Expiration == 0 {
  18. return false
  19. }
  20. return time.Now().UnixNano() > item.Expiration
  21. }
  22. const (
  23. // For use with functions that take an expiration time.
  24. NoExpiration time.Duration = -1
  25. // For use with functions that take an expiration time. Equivalent to
  26. // passing in the same expiration duration as was given to New() or
  27. // NewFrom() when the cache was created (e.g. 5 minutes.)
  28. DefaultExpiration time.Duration = 0
  29. )
  30. type Cache struct {
  31. *cache
  32. // If this is confusing, see the comment at the bottom of New()
  33. }
  34. type cache struct {
  35. defaultExpiration time.Duration
  36. items map[string]Item
  37. mu sync.RWMutex
  38. onEvicted func(string, interface{})
  39. janitor *janitor
  40. }
  41. // Add an item to the cache, replacing any existing item. If the duration is 0
  42. // (DefaultExpiration), the cache's default expiration time is used. If it is -1
  43. // (NoExpiration), the item never expires.
  44. func (c *cache) Set(k string, x interface{}, d time.Duration) {
  45. // "Inlining" of set
  46. var e int64
  47. if d == DefaultExpiration {
  48. d = c.defaultExpiration
  49. }
  50. if d > 0 {
  51. e = time.Now().Add(d).UnixNano()
  52. }
  53. c.mu.Lock()
  54. c.items[k] = Item{
  55. Object: x,
  56. Expiration: e,
  57. }
  58. // TODO: Calls to mu.Unlock are currently not deferred because defer
  59. // adds ~200 ns (as of go1.)
  60. c.mu.Unlock()
  61. }
  62. func (c *cache) set(k string, x interface{}, d time.Duration) {
  63. var e int64
  64. if d == DefaultExpiration {
  65. d = c.defaultExpiration
  66. }
  67. if d > 0 {
  68. e = time.Now().Add(d).UnixNano()
  69. }
  70. c.items[k] = Item{
  71. Object: x,
  72. Expiration: e,
  73. }
  74. }
  75. // Add an item to the cache, replacing any existing item, using the default
  76. // expiration.
  77. func (c *cache) SetDefault(k string, x interface{}) {
  78. c.Set(k, x, DefaultExpiration)
  79. }
  80. // Add an item to the cache only if an item doesn't already exist for the given
  81. // key, or if the existing item has expired. Returns an error otherwise.
  82. func (c *cache) Add(k string, x interface{}, d time.Duration) error {
  83. c.mu.Lock()
  84. _, found := c.get(k)
  85. if found {
  86. c.mu.Unlock()
  87. return fmt.Errorf("Item %s already exists", k)
  88. }
  89. c.set(k, x, d)
  90. c.mu.Unlock()
  91. return nil
  92. }
  93. // Set a new value for the cache key only if it already exists, and the existing
  94. // item hasn't expired. Returns an error otherwise.
  95. func (c *cache) Replace(k string, x interface{}, d time.Duration) error {
  96. c.mu.Lock()
  97. _, found := c.get(k)
  98. if !found {
  99. c.mu.Unlock()
  100. return fmt.Errorf("Item %s doesn't exist", k)
  101. }
  102. c.set(k, x, d)
  103. c.mu.Unlock()
  104. return nil
  105. }
  106. // Get an item from the cache. Returns the item or nil, and a bool indicating
  107. // whether the key was found.
  108. func (c *cache) Get(k string) (interface{}, bool) {
  109. c.mu.RLock()
  110. // "Inlining" of get and Expired
  111. item, found := c.items[k]
  112. if !found {
  113. c.mu.RUnlock()
  114. return nil, false
  115. }
  116. if item.Expiration > 0 {
  117. if time.Now().UnixNano() > item.Expiration {
  118. c.mu.RUnlock()
  119. return nil, false
  120. }
  121. }
  122. c.mu.RUnlock()
  123. return item.Object, true
  124. }
  125. // GetWithExpiration returns an item and its expiration time from the cache.
  126. // It returns the item or nil, the expiration time if one is set (if the item
  127. // never expires a zero value for time.Time is returned), and a bool indicating
  128. // whether the key was found.
  129. func (c *cache) GetWithExpiration(k string) (interface{}, time.Time, bool) {
  130. c.mu.RLock()
  131. // "Inlining" of get and Expired
  132. item, found := c.items[k]
  133. if !found {
  134. c.mu.RUnlock()
  135. return nil, time.Time{}, false
  136. }
  137. if item.Expiration > 0 {
  138. if time.Now().UnixNano() > item.Expiration {
  139. c.mu.RUnlock()
  140. return nil, time.Time{}, false
  141. }
  142. // Return the item and the expiration time
  143. c.mu.RUnlock()
  144. return item.Object, time.Unix(0, item.Expiration), true
  145. }
  146. // If expiration <= 0 (i.e. no expiration time set) then return the item
  147. // and a zeroed time.Time
  148. c.mu.RUnlock()
  149. return item.Object, time.Time{}, true
  150. }
  151. func (c *cache) get(k string) (interface{}, bool) {
  152. item, found := c.items[k]
  153. if !found {
  154. return nil, false
  155. }
  156. // "Inlining" of Expired
  157. if item.Expiration > 0 {
  158. if time.Now().UnixNano() > item.Expiration {
  159. return nil, false
  160. }
  161. }
  162. return item.Object, true
  163. }
  164. // Increment an item of type int, int8, int16, int32, int64, uintptr, uint,
  165. // uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
  166. // item's value is not an integer, if it was not found, or if it is not
  167. // possible to increment it by n. To retrieve the incremented value, use one
  168. // of the specialized methods, e.g. IncrementInt64.
  169. func (c *cache) Increment(k string, n int64) error {
  170. c.mu.Lock()
  171. v, found := c.items[k]
  172. if !found || v.Expired() {
  173. c.mu.Unlock()
  174. return fmt.Errorf("Item %s not found", k)
  175. }
  176. switch v.Object.(type) {
  177. case int:
  178. v.Object = v.Object.(int) + int(n)
  179. case int8:
  180. v.Object = v.Object.(int8) + int8(n)
  181. case int16:
  182. v.Object = v.Object.(int16) + int16(n)
  183. case int32:
  184. v.Object = v.Object.(int32) + int32(n)
  185. case int64:
  186. v.Object = v.Object.(int64) + n
  187. case uint:
  188. v.Object = v.Object.(uint) + uint(n)
  189. case uintptr:
  190. v.Object = v.Object.(uintptr) + uintptr(n)
  191. case uint8:
  192. v.Object = v.Object.(uint8) + uint8(n)
  193. case uint16:
  194. v.Object = v.Object.(uint16) + uint16(n)
  195. case uint32:
  196. v.Object = v.Object.(uint32) + uint32(n)
  197. case uint64:
  198. v.Object = v.Object.(uint64) + uint64(n)
  199. case float32:
  200. v.Object = v.Object.(float32) + float32(n)
  201. case float64:
  202. v.Object = v.Object.(float64) + float64(n)
  203. default:
  204. c.mu.Unlock()
  205. return fmt.Errorf("The value for %s is not an integer", k)
  206. }
  207. c.items[k] = v
  208. c.mu.Unlock()
  209. return nil
  210. }
  211. // Increment an item of type float32 or float64 by n. Returns an error if the
  212. // item's value is not floating point, if it was not found, or if it is not
  213. // possible to increment it by n. Pass a negative number to decrement the
  214. // value. To retrieve the incremented value, use one of the specialized methods,
  215. // e.g. IncrementFloat64.
  216. func (c *cache) IncrementFloat(k string, n float64) error {
  217. c.mu.Lock()
  218. v, found := c.items[k]
  219. if !found || v.Expired() {
  220. c.mu.Unlock()
  221. return fmt.Errorf("Item %s not found", k)
  222. }
  223. switch v.Object.(type) {
  224. case float32:
  225. v.Object = v.Object.(float32) + float32(n)
  226. case float64:
  227. v.Object = v.Object.(float64) + n
  228. default:
  229. c.mu.Unlock()
  230. return fmt.Errorf("The value for %s does not have type float32 or float64", k)
  231. }
  232. c.items[k] = v
  233. c.mu.Unlock()
  234. return nil
  235. }
  236. // Increment an item of type int by n. Returns an error if the item's value is
  237. // not an int, or if it was not found. If there is no error, the incremented
  238. // value is returned.
  239. func (c *cache) IncrementInt(k string, n int) (int, error) {
  240. c.mu.Lock()
  241. v, found := c.items[k]
  242. if !found || v.Expired() {
  243. c.mu.Unlock()
  244. return 0, fmt.Errorf("Item %s not found", k)
  245. }
  246. rv, ok := v.Object.(int)
  247. if !ok {
  248. c.mu.Unlock()
  249. return 0, fmt.Errorf("The value for %s is not an int", k)
  250. }
  251. nv := rv + n
  252. v.Object = nv
  253. c.items[k] = v
  254. c.mu.Unlock()
  255. return nv, nil
  256. }
  257. // Increment an item of type int8 by n. Returns an error if the item's value is
  258. // not an int8, or if it was not found. If there is no error, the incremented
  259. // value is returned.
  260. func (c *cache) IncrementInt8(k string, n int8) (int8, error) {
  261. c.mu.Lock()
  262. v, found := c.items[k]
  263. if !found || v.Expired() {
  264. c.mu.Unlock()
  265. return 0, fmt.Errorf("Item %s not found", k)
  266. }
  267. rv, ok := v.Object.(int8)
  268. if !ok {
  269. c.mu.Unlock()
  270. return 0, fmt.Errorf("The value for %s is not an int8", k)
  271. }
  272. nv := rv + n
  273. v.Object = nv
  274. c.items[k] = v
  275. c.mu.Unlock()
  276. return nv, nil
  277. }
  278. // Increment an item of type int16 by n. Returns an error if the item's value is
  279. // not an int16, or if it was not found. If there is no error, the incremented
  280. // value is returned.
  281. func (c *cache) IncrementInt16(k string, n int16) (int16, error) {
  282. c.mu.Lock()
  283. v, found := c.items[k]
  284. if !found || v.Expired() {
  285. c.mu.Unlock()
  286. return 0, fmt.Errorf("Item %s not found", k)
  287. }
  288. rv, ok := v.Object.(int16)
  289. if !ok {
  290. c.mu.Unlock()
  291. return 0, fmt.Errorf("The value for %s is not an int16", k)
  292. }
  293. nv := rv + n
  294. v.Object = nv
  295. c.items[k] = v
  296. c.mu.Unlock()
  297. return nv, nil
  298. }
  299. // Increment an item of type int32 by n. Returns an error if the item's value is
  300. // not an int32, or if it was not found. If there is no error, the incremented
  301. // value is returned.
  302. func (c *cache) IncrementInt32(k string, n int32) (int32, error) {
  303. c.mu.Lock()
  304. v, found := c.items[k]
  305. if !found || v.Expired() {
  306. c.mu.Unlock()
  307. return 0, fmt.Errorf("Item %s not found", k)
  308. }
  309. rv, ok := v.Object.(int32)
  310. if !ok {
  311. c.mu.Unlock()
  312. return 0, fmt.Errorf("The value for %s is not an int32", k)
  313. }
  314. nv := rv + n
  315. v.Object = nv
  316. c.items[k] = v
  317. c.mu.Unlock()
  318. return nv, nil
  319. }
  320. // Increment an item of type int64 by n. Returns an error if the item's value is
  321. // not an int64, or if it was not found. If there is no error, the incremented
  322. // value is returned.
  323. func (c *cache) IncrementInt64(k string, n int64) (int64, error) {
  324. c.mu.Lock()
  325. v, found := c.items[k]
  326. if !found || v.Expired() {
  327. c.mu.Unlock()
  328. return 0, fmt.Errorf("Item %s not found", k)
  329. }
  330. rv, ok := v.Object.(int64)
  331. if !ok {
  332. c.mu.Unlock()
  333. return 0, fmt.Errorf("The value for %s is not an int64", k)
  334. }
  335. nv := rv + n
  336. v.Object = nv
  337. c.items[k] = v
  338. c.mu.Unlock()
  339. return nv, nil
  340. }
  341. // Increment an item of type uint by n. Returns an error if the item's value is
  342. // not an uint, or if it was not found. If there is no error, the incremented
  343. // value is returned.
  344. func (c *cache) IncrementUint(k string, n uint) (uint, error) {
  345. c.mu.Lock()
  346. v, found := c.items[k]
  347. if !found || v.Expired() {
  348. c.mu.Unlock()
  349. return 0, fmt.Errorf("Item %s not found", k)
  350. }
  351. rv, ok := v.Object.(uint)
  352. if !ok {
  353. c.mu.Unlock()
  354. return 0, fmt.Errorf("The value for %s is not an uint", k)
  355. }
  356. nv := rv + n
  357. v.Object = nv
  358. c.items[k] = v
  359. c.mu.Unlock()
  360. return nv, nil
  361. }
  362. // Increment an item of type uintptr by n. Returns an error if the item's value
  363. // is not an uintptr, or if it was not found. If there is no error, the
  364. // incremented value is returned.
  365. func (c *cache) IncrementUintptr(k string, n uintptr) (uintptr, error) {
  366. c.mu.Lock()
  367. v, found := c.items[k]
  368. if !found || v.Expired() {
  369. c.mu.Unlock()
  370. return 0, fmt.Errorf("Item %s not found", k)
  371. }
  372. rv, ok := v.Object.(uintptr)
  373. if !ok {
  374. c.mu.Unlock()
  375. return 0, fmt.Errorf("The value for %s is not an uintptr", k)
  376. }
  377. nv := rv + n
  378. v.Object = nv
  379. c.items[k] = v
  380. c.mu.Unlock()
  381. return nv, nil
  382. }
  383. // Increment an item of type uint8 by n. Returns an error if the item's value
  384. // is not an uint8, or if it was not found. If there is no error, the
  385. // incremented value is returned.
  386. func (c *cache) IncrementUint8(k string, n uint8) (uint8, error) {
  387. c.mu.Lock()
  388. v, found := c.items[k]
  389. if !found || v.Expired() {
  390. c.mu.Unlock()
  391. return 0, fmt.Errorf("Item %s not found", k)
  392. }
  393. rv, ok := v.Object.(uint8)
  394. if !ok {
  395. c.mu.Unlock()
  396. return 0, fmt.Errorf("The value for %s is not an uint8", k)
  397. }
  398. nv := rv + n
  399. v.Object = nv
  400. c.items[k] = v
  401. c.mu.Unlock()
  402. return nv, nil
  403. }
  404. // Increment an item of type uint16 by n. Returns an error if the item's value
  405. // is not an uint16, or if it was not found. If there is no error, the
  406. // incremented value is returned.
  407. func (c *cache) IncrementUint16(k string, n uint16) (uint16, error) {
  408. c.mu.Lock()
  409. v, found := c.items[k]
  410. if !found || v.Expired() {
  411. c.mu.Unlock()
  412. return 0, fmt.Errorf("Item %s not found", k)
  413. }
  414. rv, ok := v.Object.(uint16)
  415. if !ok {
  416. c.mu.Unlock()
  417. return 0, fmt.Errorf("The value for %s is not an uint16", k)
  418. }
  419. nv := rv + n
  420. v.Object = nv
  421. c.items[k] = v
  422. c.mu.Unlock()
  423. return nv, nil
  424. }
  425. // Increment an item of type uint32 by n. Returns an error if the item's value
  426. // is not an uint32, or if it was not found. If there is no error, the
  427. // incremented value is returned.
  428. func (c *cache) IncrementUint32(k string, n uint32) (uint32, error) {
  429. c.mu.Lock()
  430. v, found := c.items[k]
  431. if !found || v.Expired() {
  432. c.mu.Unlock()
  433. return 0, fmt.Errorf("Item %s not found", k)
  434. }
  435. rv, ok := v.Object.(uint32)
  436. if !ok {
  437. c.mu.Unlock()
  438. return 0, fmt.Errorf("The value for %s is not an uint32", k)
  439. }
  440. nv := rv + n
  441. v.Object = nv
  442. c.items[k] = v
  443. c.mu.Unlock()
  444. return nv, nil
  445. }
  446. // Increment an item of type uint64 by n. Returns an error if the item's value
  447. // is not an uint64, or if it was not found. If there is no error, the
  448. // incremented value is returned.
  449. func (c *cache) IncrementUint64(k string, n uint64) (uint64, error) {
  450. c.mu.Lock()
  451. v, found := c.items[k]
  452. if !found || v.Expired() {
  453. c.mu.Unlock()
  454. return 0, fmt.Errorf("Item %s not found", k)
  455. }
  456. rv, ok := v.Object.(uint64)
  457. if !ok {
  458. c.mu.Unlock()
  459. return 0, fmt.Errorf("The value for %s is not an uint64", k)
  460. }
  461. nv := rv + n
  462. v.Object = nv
  463. c.items[k] = v
  464. c.mu.Unlock()
  465. return nv, nil
  466. }
  467. // Increment an item of type float32 by n. Returns an error if the item's value
  468. // is not an float32, or if it was not found. If there is no error, the
  469. // incremented value is returned.
  470. func (c *cache) IncrementFloat32(k string, n float32) (float32, error) {
  471. c.mu.Lock()
  472. v, found := c.items[k]
  473. if !found || v.Expired() {
  474. c.mu.Unlock()
  475. return 0, fmt.Errorf("Item %s not found", k)
  476. }
  477. rv, ok := v.Object.(float32)
  478. if !ok {
  479. c.mu.Unlock()
  480. return 0, fmt.Errorf("The value for %s is not an float32", k)
  481. }
  482. nv := rv + n
  483. v.Object = nv
  484. c.items[k] = v
  485. c.mu.Unlock()
  486. return nv, nil
  487. }
  488. // Increment an item of type float64 by n. Returns an error if the item's value
  489. // is not an float64, or if it was not found. If there is no error, the
  490. // incremented value is returned.
  491. func (c *cache) IncrementFloat64(k string, n float64) (float64, error) {
  492. c.mu.Lock()
  493. v, found := c.items[k]
  494. if !found || v.Expired() {
  495. c.mu.Unlock()
  496. return 0, fmt.Errorf("Item %s not found", k)
  497. }
  498. rv, ok := v.Object.(float64)
  499. if !ok {
  500. c.mu.Unlock()
  501. return 0, fmt.Errorf("The value for %s is not an float64", k)
  502. }
  503. nv := rv + n
  504. v.Object = nv
  505. c.items[k] = v
  506. c.mu.Unlock()
  507. return nv, nil
  508. }
  509. // Decrement an item of type int, int8, int16, int32, int64, uintptr, uint,
  510. // uint8, uint32, or uint64, float32 or float64 by n. Returns an error if the
  511. // item's value is not an integer, if it was not found, or if it is not
  512. // possible to decrement it by n. To retrieve the decremented value, use one
  513. // of the specialized methods, e.g. DecrementInt64.
  514. func (c *cache) Decrement(k string, n int64) error {
  515. // TODO: Implement Increment and Decrement more cleanly.
  516. // (Cannot do Increment(k, n*-1) for uints.)
  517. c.mu.Lock()
  518. v, found := c.items[k]
  519. if !found || v.Expired() {
  520. c.mu.Unlock()
  521. return fmt.Errorf("Item not found")
  522. }
  523. switch v.Object.(type) {
  524. case int:
  525. v.Object = v.Object.(int) - int(n)
  526. case int8:
  527. v.Object = v.Object.(int8) - int8(n)
  528. case int16:
  529. v.Object = v.Object.(int16) - int16(n)
  530. case int32:
  531. v.Object = v.Object.(int32) - int32(n)
  532. case int64:
  533. v.Object = v.Object.(int64) - n
  534. case uint:
  535. v.Object = v.Object.(uint) - uint(n)
  536. case uintptr:
  537. v.Object = v.Object.(uintptr) - uintptr(n)
  538. case uint8:
  539. v.Object = v.Object.(uint8) - uint8(n)
  540. case uint16:
  541. v.Object = v.Object.(uint16) - uint16(n)
  542. case uint32:
  543. v.Object = v.Object.(uint32) - uint32(n)
  544. case uint64:
  545. v.Object = v.Object.(uint64) - uint64(n)
  546. case float32:
  547. v.Object = v.Object.(float32) - float32(n)
  548. case float64:
  549. v.Object = v.Object.(float64) - float64(n)
  550. default:
  551. c.mu.Unlock()
  552. return fmt.Errorf("The value for %s is not an integer", k)
  553. }
  554. c.items[k] = v
  555. c.mu.Unlock()
  556. return nil
  557. }
  558. // Decrement an item of type float32 or float64 by n. Returns an error if the
  559. // item's value is not floating point, if it was not found, or if it is not
  560. // possible to decrement it by n. Pass a negative number to decrement the
  561. // value. To retrieve the decremented value, use one of the specialized methods,
  562. // e.g. DecrementFloat64.
  563. func (c *cache) DecrementFloat(k string, n float64) error {
  564. c.mu.Lock()
  565. v, found := c.items[k]
  566. if !found || v.Expired() {
  567. c.mu.Unlock()
  568. return fmt.Errorf("Item %s not found", k)
  569. }
  570. switch v.Object.(type) {
  571. case float32:
  572. v.Object = v.Object.(float32) - float32(n)
  573. case float64:
  574. v.Object = v.Object.(float64) - n
  575. default:
  576. c.mu.Unlock()
  577. return fmt.Errorf("The value for %s does not have type float32 or float64", k)
  578. }
  579. c.items[k] = v
  580. c.mu.Unlock()
  581. return nil
  582. }
  583. // Decrement an item of type int by n. Returns an error if the item's value is
  584. // not an int, or if it was not found. If there is no error, the decremented
  585. // value is returned.
  586. func (c *cache) DecrementInt(k string, n int) (int, error) {
  587. c.mu.Lock()
  588. v, found := c.items[k]
  589. if !found || v.Expired() {
  590. c.mu.Unlock()
  591. return 0, fmt.Errorf("Item %s not found", k)
  592. }
  593. rv, ok := v.Object.(int)
  594. if !ok {
  595. c.mu.Unlock()
  596. return 0, fmt.Errorf("The value for %s is not an int", k)
  597. }
  598. nv := rv - n
  599. v.Object = nv
  600. c.items[k] = v
  601. c.mu.Unlock()
  602. return nv, nil
  603. }
  604. // Decrement an item of type int8 by n. Returns an error if the item's value is
  605. // not an int8, or if it was not found. If there is no error, the decremented
  606. // value is returned.
  607. func (c *cache) DecrementInt8(k string, n int8) (int8, error) {
  608. c.mu.Lock()
  609. v, found := c.items[k]
  610. if !found || v.Expired() {
  611. c.mu.Unlock()
  612. return 0, fmt.Errorf("Item %s not found", k)
  613. }
  614. rv, ok := v.Object.(int8)
  615. if !ok {
  616. c.mu.Unlock()
  617. return 0, fmt.Errorf("The value for %s is not an int8", k)
  618. }
  619. nv := rv - n
  620. v.Object = nv
  621. c.items[k] = v
  622. c.mu.Unlock()
  623. return nv, nil
  624. }
  625. // Decrement an item of type int16 by n. Returns an error if the item's value is
  626. // not an int16, or if it was not found. If there is no error, the decremented
  627. // value is returned.
  628. func (c *cache) DecrementInt16(k string, n int16) (int16, error) {
  629. c.mu.Lock()
  630. v, found := c.items[k]
  631. if !found || v.Expired() {
  632. c.mu.Unlock()
  633. return 0, fmt.Errorf("Item %s not found", k)
  634. }
  635. rv, ok := v.Object.(int16)
  636. if !ok {
  637. c.mu.Unlock()
  638. return 0, fmt.Errorf("The value for %s is not an int16", k)
  639. }
  640. nv := rv - n
  641. v.Object = nv
  642. c.items[k] = v
  643. c.mu.Unlock()
  644. return nv, nil
  645. }
  646. // Decrement an item of type int32 by n. Returns an error if the item's value is
  647. // not an int32, or if it was not found. If there is no error, the decremented
  648. // value is returned.
  649. func (c *cache) DecrementInt32(k string, n int32) (int32, error) {
  650. c.mu.Lock()
  651. v, found := c.items[k]
  652. if !found || v.Expired() {
  653. c.mu.Unlock()
  654. return 0, fmt.Errorf("Item %s not found", k)
  655. }
  656. rv, ok := v.Object.(int32)
  657. if !ok {
  658. c.mu.Unlock()
  659. return 0, fmt.Errorf("The value for %s is not an int32", k)
  660. }
  661. nv := rv - n
  662. v.Object = nv
  663. c.items[k] = v
  664. c.mu.Unlock()
  665. return nv, nil
  666. }
  667. // Decrement an item of type int64 by n. Returns an error if the item's value is
  668. // not an int64, or if it was not found. If there is no error, the decremented
  669. // value is returned.
  670. func (c *cache) DecrementInt64(k string, n int64) (int64, error) {
  671. c.mu.Lock()
  672. v, found := c.items[k]
  673. if !found || v.Expired() {
  674. c.mu.Unlock()
  675. return 0, fmt.Errorf("Item %s not found", k)
  676. }
  677. rv, ok := v.Object.(int64)
  678. if !ok {
  679. c.mu.Unlock()
  680. return 0, fmt.Errorf("The value for %s is not an int64", k)
  681. }
  682. nv := rv - n
  683. v.Object = nv
  684. c.items[k] = v
  685. c.mu.Unlock()
  686. return nv, nil
  687. }
  688. // Decrement an item of type uint by n. Returns an error if the item's value is
  689. // not an uint, or if it was not found. If there is no error, the decremented
  690. // value is returned.
  691. func (c *cache) DecrementUint(k string, n uint) (uint, error) {
  692. c.mu.Lock()
  693. v, found := c.items[k]
  694. if !found || v.Expired() {
  695. c.mu.Unlock()
  696. return 0, fmt.Errorf("Item %s not found", k)
  697. }
  698. rv, ok := v.Object.(uint)
  699. if !ok {
  700. c.mu.Unlock()
  701. return 0, fmt.Errorf("The value for %s is not an uint", k)
  702. }
  703. nv := rv - n
  704. v.Object = nv
  705. c.items[k] = v
  706. c.mu.Unlock()
  707. return nv, nil
  708. }
  709. // Decrement an item of type uintptr by n. Returns an error if the item's value
  710. // is not an uintptr, or if it was not found. If there is no error, the
  711. // decremented value is returned.
  712. func (c *cache) DecrementUintptr(k string, n uintptr) (uintptr, error) {
  713. c.mu.Lock()
  714. v, found := c.items[k]
  715. if !found || v.Expired() {
  716. c.mu.Unlock()
  717. return 0, fmt.Errorf("Item %s not found", k)
  718. }
  719. rv, ok := v.Object.(uintptr)
  720. if !ok {
  721. c.mu.Unlock()
  722. return 0, fmt.Errorf("The value for %s is not an uintptr", k)
  723. }
  724. nv := rv - n
  725. v.Object = nv
  726. c.items[k] = v
  727. c.mu.Unlock()
  728. return nv, nil
  729. }
  730. // Decrement an item of type uint8 by n. Returns an error if the item's value is
  731. // not an uint8, or if it was not found. If there is no error, the decremented
  732. // value is returned.
  733. func (c *cache) DecrementUint8(k string, n uint8) (uint8, error) {
  734. c.mu.Lock()
  735. v, found := c.items[k]
  736. if !found || v.Expired() {
  737. c.mu.Unlock()
  738. return 0, fmt.Errorf("Item %s not found", k)
  739. }
  740. rv, ok := v.Object.(uint8)
  741. if !ok {
  742. c.mu.Unlock()
  743. return 0, fmt.Errorf("The value for %s is not an uint8", k)
  744. }
  745. nv := rv - n
  746. v.Object = nv
  747. c.items[k] = v
  748. c.mu.Unlock()
  749. return nv, nil
  750. }
  751. // Decrement an item of type uint16 by n. Returns an error if the item's value
  752. // is not an uint16, or if it was not found. If there is no error, the
  753. // decremented value is returned.
  754. func (c *cache) DecrementUint16(k string, n uint16) (uint16, error) {
  755. c.mu.Lock()
  756. v, found := c.items[k]
  757. if !found || v.Expired() {
  758. c.mu.Unlock()
  759. return 0, fmt.Errorf("Item %s not found", k)
  760. }
  761. rv, ok := v.Object.(uint16)
  762. if !ok {
  763. c.mu.Unlock()
  764. return 0, fmt.Errorf("The value for %s is not an uint16", k)
  765. }
  766. nv := rv - n
  767. v.Object = nv
  768. c.items[k] = v
  769. c.mu.Unlock()
  770. return nv, nil
  771. }
  772. // Decrement an item of type uint32 by n. Returns an error if the item's value
  773. // is not an uint32, or if it was not found. If there is no error, the
  774. // decremented value is returned.
  775. func (c *cache) DecrementUint32(k string, n uint32) (uint32, error) {
  776. c.mu.Lock()
  777. v, found := c.items[k]
  778. if !found || v.Expired() {
  779. c.mu.Unlock()
  780. return 0, fmt.Errorf("Item %s not found", k)
  781. }
  782. rv, ok := v.Object.(uint32)
  783. if !ok {
  784. c.mu.Unlock()
  785. return 0, fmt.Errorf("The value for %s is not an uint32", k)
  786. }
  787. nv := rv - n
  788. v.Object = nv
  789. c.items[k] = v
  790. c.mu.Unlock()
  791. return nv, nil
  792. }
  793. // Decrement an item of type uint64 by n. Returns an error if the item's value
  794. // is not an uint64, or if it was not found. If there is no error, the
  795. // decremented value is returned.
  796. func (c *cache) DecrementUint64(k string, n uint64) (uint64, error) {
  797. c.mu.Lock()
  798. v, found := c.items[k]
  799. if !found || v.Expired() {
  800. c.mu.Unlock()
  801. return 0, fmt.Errorf("Item %s not found", k)
  802. }
  803. rv, ok := v.Object.(uint64)
  804. if !ok {
  805. c.mu.Unlock()
  806. return 0, fmt.Errorf("The value for %s is not an uint64", k)
  807. }
  808. nv := rv - n
  809. v.Object = nv
  810. c.items[k] = v
  811. c.mu.Unlock()
  812. return nv, nil
  813. }
  814. // Decrement an item of type float32 by n. Returns an error if the item's value
  815. // is not an float32, or if it was not found. If there is no error, the
  816. // decremented value is returned.
  817. func (c *cache) DecrementFloat32(k string, n float32) (float32, error) {
  818. c.mu.Lock()
  819. v, found := c.items[k]
  820. if !found || v.Expired() {
  821. c.mu.Unlock()
  822. return 0, fmt.Errorf("Item %s not found", k)
  823. }
  824. rv, ok := v.Object.(float32)
  825. if !ok {
  826. c.mu.Unlock()
  827. return 0, fmt.Errorf("The value for %s is not an float32", k)
  828. }
  829. nv := rv - n
  830. v.Object = nv
  831. c.items[k] = v
  832. c.mu.Unlock()
  833. return nv, nil
  834. }
  835. // Decrement an item of type float64 by n. Returns an error if the item's value
  836. // is not an float64, or if it was not found. If there is no error, the
  837. // decremented value is returned.
  838. func (c *cache) DecrementFloat64(k string, n float64) (float64, error) {
  839. c.mu.Lock()
  840. v, found := c.items[k]
  841. if !found || v.Expired() {
  842. c.mu.Unlock()
  843. return 0, fmt.Errorf("Item %s not found", k)
  844. }
  845. rv, ok := v.Object.(float64)
  846. if !ok {
  847. c.mu.Unlock()
  848. return 0, fmt.Errorf("The value for %s is not an float64", k)
  849. }
  850. nv := rv - n
  851. v.Object = nv
  852. c.items[k] = v
  853. c.mu.Unlock()
  854. return nv, nil
  855. }
  856. // Delete an item from the cache. Does nothing if the key is not in the cache.
  857. func (c *cache) Delete(k string) {
  858. c.mu.Lock()
  859. v, evicted := c.delete(k)
  860. c.mu.Unlock()
  861. if evicted {
  862. c.onEvicted(k, v)
  863. }
  864. }
  865. func (c *cache) delete(k string) (interface{}, bool) {
  866. if c.onEvicted != nil {
  867. if v, found := c.items[k]; found {
  868. delete(c.items, k)
  869. return v.Object, true
  870. }
  871. }
  872. delete(c.items, k)
  873. return nil, false
  874. }
  875. type keyAndValue struct {
  876. key string
  877. value interface{}
  878. }
  879. // Delete all expired items from the cache.
  880. func (c *cache) DeleteExpired() {
  881. var evictedItems []keyAndValue
  882. now := time.Now().UnixNano()
  883. c.mu.Lock()
  884. for k, v := range c.items {
  885. // "Inlining" of expired
  886. if v.Expiration > 0 && now > v.Expiration {
  887. ov, evicted := c.delete(k)
  888. if evicted {
  889. evictedItems = append(evictedItems, keyAndValue{k, ov})
  890. }
  891. }
  892. }
  893. c.mu.Unlock()
  894. for _, v := range evictedItems {
  895. c.onEvicted(v.key, v.value)
  896. }
  897. }
  898. // Sets an (optional) function that is called with the key and value when an
  899. // item is evicted from the cache. (Including when it is deleted manually, but
  900. // not when it is overwritten.) Set to nil to disable.
  901. func (c *cache) OnEvicted(f func(string, interface{})) {
  902. c.mu.Lock()
  903. c.onEvicted = f
  904. c.mu.Unlock()
  905. }
  906. // Write the cache's items (using Gob) to an io.Writer.
  907. //
  908. // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  909. // documentation for NewFrom().)
  910. func (c *cache) Save(w io.Writer) (err error) {
  911. enc := gob.NewEncoder(w)
  912. defer func() {
  913. if x := recover(); x != nil {
  914. err = fmt.Errorf("Error registering item types with Gob library")
  915. }
  916. }()
  917. c.mu.RLock()
  918. defer c.mu.RUnlock()
  919. for _, v := range c.items {
  920. gob.Register(v.Object)
  921. }
  922. err = enc.Encode(&c.items)
  923. return
  924. }
  925. // Save the cache's items to the given filename, creating the file if it
  926. // doesn't exist, and overwriting it if it does.
  927. //
  928. // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  929. // documentation for NewFrom().)
  930. func (c *cache) SaveFile(fname string) error {
  931. fp, err := os.Create(fname)
  932. if err != nil {
  933. return err
  934. }
  935. err = c.Save(fp)
  936. if err != nil {
  937. fp.Close()
  938. return err
  939. }
  940. return fp.Close()
  941. }
  942. // Add (Gob-serialized) cache items from an io.Reader, excluding any items with
  943. // keys that already exist (and haven't expired) in the current cache.
  944. //
  945. // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  946. // documentation for NewFrom().)
  947. func (c *cache) Load(r io.Reader) error {
  948. dec := gob.NewDecoder(r)
  949. items := map[string]Item{}
  950. err := dec.Decode(&items)
  951. if err == nil {
  952. c.mu.Lock()
  953. defer c.mu.Unlock()
  954. for k, v := range items {
  955. ov, found := c.items[k]
  956. if !found || ov.Expired() {
  957. c.items[k] = v
  958. }
  959. }
  960. }
  961. return err
  962. }
  963. // Load and add cache items from the given filename, excluding any items with
  964. // keys that already exist in the current cache.
  965. //
  966. // NOTE: This method is deprecated in favor of c.Items() and NewFrom() (see the
  967. // documentation for NewFrom().)
  968. func (c *cache) LoadFile(fname string) error {
  969. fp, err := os.Open(fname)
  970. if err != nil {
  971. return err
  972. }
  973. err = c.Load(fp)
  974. if err != nil {
  975. fp.Close()
  976. return err
  977. }
  978. return fp.Close()
  979. }
  980. // Copies all unexpired items in the cache into a new map and returns it.
  981. func (c *cache) Items() map[string]Item {
  982. c.mu.RLock()
  983. defer c.mu.RUnlock()
  984. m := make(map[string]Item, len(c.items))
  985. now := time.Now().UnixNano()
  986. for k, v := range c.items {
  987. // "Inlining" of Expired
  988. if v.Expiration > 0 {
  989. if now > v.Expiration {
  990. continue
  991. }
  992. }
  993. m[k] = v
  994. }
  995. return m
  996. }
  997. // Returns the number of items in the cache. This may include items that have
  998. // expired, but have not yet been cleaned up.
  999. func (c *cache) ItemCount() int {
  1000. c.mu.RLock()
  1001. n := len(c.items)
  1002. c.mu.RUnlock()
  1003. return n
  1004. }
  1005. // Delete all items from the cache.
  1006. func (c *cache) Flush() {
  1007. c.mu.Lock()
  1008. c.items = map[string]Item{}
  1009. c.mu.Unlock()
  1010. }
  1011. type janitor struct {
  1012. Interval time.Duration
  1013. stop chan bool
  1014. }
  1015. func (j *janitor) Run(c *cache) {
  1016. ticker := time.NewTicker(j.Interval)
  1017. for {
  1018. select {
  1019. case <-ticker.C:
  1020. c.DeleteExpired()
  1021. case <-j.stop:
  1022. ticker.Stop()
  1023. return
  1024. }
  1025. }
  1026. }
  1027. func stopJanitor(c *Cache) {
  1028. c.janitor.stop <- true
  1029. }
  1030. func runJanitor(c *cache, ci time.Duration) {
  1031. j := &janitor{
  1032. Interval: ci,
  1033. stop: make(chan bool),
  1034. }
  1035. c.janitor = j
  1036. go j.Run(c)
  1037. }
  1038. func newCache(de time.Duration, m map[string]Item) *cache {
  1039. if de == 0 {
  1040. de = -1
  1041. }
  1042. c := &cache{
  1043. defaultExpiration: de,
  1044. items: m,
  1045. }
  1046. return c
  1047. }
  1048. func newCacheWithJanitor(de time.Duration, ci time.Duration, m map[string]Item) *Cache {
  1049. c := newCache(de, m)
  1050. // This trick ensures that the janitor goroutine (which--granted it
  1051. // was enabled--is running DeleteExpired on c forever) does not keep
  1052. // the returned C object from being garbage collected. When it is
  1053. // garbage collected, the finalizer stops the janitor goroutine, after
  1054. // which c can be collected.
  1055. C := &Cache{c}
  1056. if ci > 0 {
  1057. runJanitor(c, ci)
  1058. runtime.SetFinalizer(C, stopJanitor)
  1059. }
  1060. return C
  1061. }
  1062. // Return a new cache with a given default expiration duration and cleanup
  1063. // interval. If the expiration duration is less than one (or NoExpiration),
  1064. // the items in the cache never expire (by default), and must be deleted
  1065. // manually. If the cleanup interval is less than one, expired items are not
  1066. // deleted from the cache before calling c.DeleteExpired().
  1067. func New(defaultExpiration, cleanupInterval time.Duration) *Cache {
  1068. items := make(map[string]Item)
  1069. return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
  1070. }
  1071. // Return a new cache with a given default expiration duration and cleanup
  1072. // interval. If the expiration duration is less than one (or NoExpiration),
  1073. // the items in the cache never expire (by default), and must be deleted
  1074. // manually. If the cleanup interval is less than one, expired items are not
  1075. // deleted from the cache before calling c.DeleteExpired().
  1076. //
  1077. // NewFrom() also accepts an items map which will serve as the underlying map
  1078. // for the cache. This is useful for starting from a deserialized cache
  1079. // (serialized using e.g. gob.Encode() on c.Items()), or passing in e.g.
  1080. // make(map[string]Item, 500) to improve startup performance when the cache
  1081. // is expected to reach a certain minimum size.
  1082. //
  1083. // Only the cache's methods synchronize access to this map, so it is not
  1084. // recommended to keep any references to the map around after creating a cache.
  1085. // If need be, the map can be accessed at a later point using c.Items() (subject
  1086. // to the same caveat.)
  1087. //
  1088. // Note regarding serialization: When using e.g. gob, make sure to
  1089. // gob.Register() the individual types stored in the cache before encoding a
  1090. // map retrieved with c.Items(), and to register those same types before
  1091. // decoding a blob containing an items map.
  1092. func NewFrom(defaultExpiration, cleanupInterval time.Duration, items map[string]Item) *Cache {
  1093. return newCacheWithJanitor(defaultExpiration, cleanupInterval, items)
  1094. }