lru.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * This file is part of the storage node for the Joystream project.
  3. * Copyright (C) 2019 Joystream Contributors
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation, either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. 'use strict'
  19. const expect = require('chai').expect
  20. const lru = require('@joystream/storage-utils/lru')
  21. const DEFAULT_SLEEP = 1
  22. function sleep(ms = DEFAULT_SLEEP) {
  23. return new Promise((resolve) => {
  24. setTimeout(resolve, ms)
  25. })
  26. }
  27. describe('util/lru', function () {
  28. describe('simple usage', function () {
  29. it('does not contain keys that were not added', function () {
  30. const cache = new lru.LRUCache()
  31. expect(cache.size()).to.equal(0)
  32. const val = cache.get('something')
  33. expect(val).to.be.undefined
  34. expect(cache.has('something')).to.be.false
  35. })
  36. it('contains keys that were added', function () {
  37. const cache = new lru.LRUCache()
  38. cache.put('something', 'yay!')
  39. expect(cache.size()).to.equal(1)
  40. const val = cache.get('something')
  41. expect(val).to.be.equal('yay!')
  42. expect(cache.has('something')).to.be.true
  43. })
  44. it('does not contain keys that were deleted', function () {
  45. const cache = new lru.LRUCache()
  46. cache.put('something', 'yay!')
  47. expect(cache.size()).to.equal(1)
  48. let val = cache.get('something')
  49. expect(val).to.be.equal('yay!')
  50. expect(cache.has('something')).to.be.true
  51. cache.del('something')
  52. expect(cache.size()).to.equal(0)
  53. val = cache.get('something')
  54. expect(val).to.be.undefined
  55. expect(cache.has('something')).to.be.false
  56. })
  57. it('can be cleared', function () {
  58. const cache = new lru.LRUCache()
  59. cache.put('something', 'yay!')
  60. expect(cache.size()).to.equal(1)
  61. cache.clear()
  62. expect(cache.size()).to.equal(0)
  63. })
  64. })
  65. describe('capacity management', function () {
  66. it('does not grow beyond capacity', async function () {
  67. const cache = new lru.LRUCache(2) // Small capacity
  68. expect(cache.size()).to.equal(0)
  69. cache.put('foo', '42')
  70. expect(cache.size()).to.equal(1)
  71. await sleep()
  72. cache.put('bar', '42')
  73. expect(cache.size()).to.equal(2)
  74. await sleep()
  75. cache.put('baz', '42')
  76. expect(cache.size()).to.equal(2) // Capacity exceeded
  77. })
  78. it('removes the oldest key when pruning', async function () {
  79. const cache = new lru.LRUCache(2) // Small capacity
  80. expect(cache.size()).to.equal(0)
  81. cache.put('foo', '42')
  82. expect(cache.size()).to.equal(1)
  83. expect(cache.has('foo')).to.be.true
  84. await sleep()
  85. cache.put('bar', '42')
  86. expect(cache.size()).to.equal(2)
  87. expect(cache.has('foo')).to.be.true
  88. expect(cache.has('bar')).to.be.true
  89. await sleep()
  90. cache.put('baz', '42')
  91. expect(cache.size()).to.equal(2) // Capacity exceeded
  92. expect(cache.has('bar')).to.be.true
  93. expect(cache.has('baz')).to.be.true
  94. })
  95. it('updates LRU timestamp when reading', async function () {
  96. const cache = new lru.LRUCache(2) // Small capacity
  97. expect(cache.size()).to.equal(0)
  98. cache.put('foo', '42')
  99. expect(cache.size()).to.equal(1)
  100. expect(cache.has('foo')).to.be.true
  101. await sleep()
  102. cache.put('bar', '42')
  103. expect(cache.size()).to.equal(2)
  104. expect(cache.has('foo')).to.be.true
  105. expect(cache.has('bar')).to.be.true
  106. await sleep()
  107. // 'foo' is older than 'bar' right now, so should be pruned first. But
  108. // if we get 'foo', it would be 'bar' that has to go.
  109. cache.get('foo')
  110. // Makes debugging a bit more obvious
  111. await sleep()
  112. cache.put('baz', '42')
  113. expect(cache.size()).to.equal(2) // Capacity exceeded
  114. expect(cache.has('foo')).to.be.true
  115. expect(cache.has('baz')).to.be.true
  116. })
  117. })
  118. })