Skip to content

Latest commit

 

History

History
989 lines (702 loc) · 35.2 KB

CHANGELOG.md

File metadata and controls

989 lines (702 loc) · 35.2 KB

Moka Cache — Change Log

Version 0.12.8

Fixed

  • Avoid to use recent versions (v0.1.12 or newer) of triomphe crate to keep our MSRV (Minimum Supported Rust Version) at Rust 1.65 (#426, by @eaufavor).
    • triomphe@v0.1.12 requires Rust 1.76 or newer, so it will not compile with our MSRV.
  • docs: Fix per-entry expiration policy documentation (#421, by @arcstur).

Version 0.12.7

Changed

  • Ensure a single call to run_pending_tasks to evict as many entries as possible from the cache (#417).

Version 0.12.6

Fixed

  • Fixed a bug in future::Cache that pending run_pending_tasks calls may cause infinite busy loop in an internal schedule_write_op method (#412):
    • This bug was introduced in v0.12.0 when the background threads were removed from future::Cache.
    • This bug can occur when run_pending_task method is called by user code while cache is receiving a very high number of concurrent cache write operations. (e.g. insert, get_with, invalidate etc.)
    • When it occurs, the schedule_write_op method will be spinning in a busy loop forever, causing high CPU usage and all other async tasks to be starved.

Changed

  • Upgraded async-lock crate used by future::Cache from v2.4 to the latest v3.3.

Version 0.12.5

Added

  • Added support for a plain LRU (Least Recently Used) eviction policy (#390):
    • The LRU policy is enabled by calling the eviction_policy method of the cache builder with a policy obtained by EvictionPolicy::lru function.
    • The default eviction policy remains the TinyLFU (Tiny, Least Frequently Used) as it maintains better hit rate than LRU for most use cases. TinyLFU combines LRU eviction policy and popularity-based admission policy. A probabilistic data structure is used to estimate historical popularity of both hit and missed keys. (not only the keys currently in the cache.)
    • However, some use cases may prefer LRU policy over TinyLFU. An example is recency biased workload such as streaming data processing. LRU policy can be used for them to achieve better hit rate.
    • Note that we are planning to add an adaptive eviction/admission policy called Window-TinyLFU in the future. It will adjust the balance between recency and frequency based on the current workload.

Version 0.12.4

Fixed

  • Ensure crossbeam-epoch to run GC when dropping a cache (#384):
    • crossbeam-epoch crate provides an epoch-based memory reclamation scheme for concurrent data structures. It is used by Moka cache to safely drop cached entries while they are still being accessed by other threads.
    • crossbeam-epoch does its best to reclaim memory (drop the entries evicted from the cache) when the epoch is advanced. However, it does not guarantee that memory will be reclaimed immediately after the epoch is advanced. This means that entries can remain in the memory for a while after the cache is dropped.
    • This fix ensures that, when a cache is dropped, the epoch is advanced and crossbeam-epoch's thread local buffers are flushed, helping to reclaim memory immediately.
    • Note that there are still chances that some entries remain in the memory for a while after a cache is dropped. We are looking for alternatives to crossbeam-epoch to improve this situation (e.g. #385).

Added

  • Added an example for reinserting expired entries to the cache. (#382)

Version 0.12.3

Added

  • Added the upsert and compute methods for modifying a cached entry (#370):
    • Now the entry and entry_by_ref APIs have the following methods:
      • and_upsert_with method to insert or update the entry.
      • and_compute_with method to insert, update, remove or do nothing on the entry.
      • and_try_compute_with method, which is similar to above but returns Result.

Fixed

  • Raised the version requirement of the quanta from >=0.11.0, <0.12.0 to >=0.12.2, <0.13.0 to avoid under-measuring the elapsed time on Apple silicon Macs (#376).
    • Due to this under-measurement, cached entries on macOS arm64 can expire sightly later than expected.

Version 0.12.2

Fixed

  • Prevent timing issues in writes that cause inconsistencies between the cache's internal data structures (#348):
    • One way to trigger the issue is that insert the same key twice quickly, once when the cache is full and a second time when there is a room in the cache.
      • When it occurs, the cache will not return the value inserted in the second call (which is wrong), and the entry_count method will keep returning a non zero value after calling the invalidate_all method (which is also wrong).
  • Now the last access time of a cached entry is updated immediately after the entry is read (#363):
    • When the time-to-idle of a cache is set, the last access time of a cached entry is used to determine if the entry has been expired.
    • Before this fix, the access time was updated (to the time when it was read) when pending tasks were processed. This delay caused issue that some entries become temporarily unavailable for reads even though they have been accessed recently. And then they will become available again after the pending tasks are processed.
    • Now the last access time is updated immediately after the entry is read. The entry will remain valid until the time-to-idle has elapsed.

Note that both of #348 and #363 were already present in v0.11.x and older versions. However they were less likely to occur because they had background threads to periodically process pending tasks. So there were much shorter time windows for these issues to occur.

Changed

  • Updated the Rust edition from 2018 to 2021. (#339, by @nyurik)
    • The MSRV remains at Rust 1.65.
  • Changed to use inline format arguments throughout the code, including examples. (#340, by @nyurik)

Added

Version 0.12.1

Fixed

  • Fixed memory leak in future::Cache that occurred when get_with(), entry().or_insert_with(), and similar methods were used (#329).
    • This bug was introduced in v0.12.0. Versions prior to v0.12.0 do not have this bug.

Changed

  • (Performance) Micro-optimize ValueInitializer (#331, by @Swatinem).

Version 0.12.0

Note v0.12.0 has major breaking changes on the API and internal behavior.

  • sync caches are no longer enabled by default: Please use a crate feature sync to enable it.

  • No more background threads: All cache types future::Cache, sync::Cache, and sync::SegmentedCache no longer spawn background threads.

    • The scheduled-thread-pool crate was removed from the dependency.
    • Because of this change, many private methods and some public methods under the future module were converted to async methods. You may need to add .await to your code for those methods.
  • Immediate notification delivery: The notification::DeliveryMode enum for the eviction listener was removed. Now all cache types behave as if the Immediate delivery mode is specified.

Please read the MIGRATION-GUIDE.md for more details.

Changed

  • Removed the thread pool from future cache (#294) and sync caches (#316).
  • Improved async cancellation safety of future::Cache. (#309)

Fixed

  • Fixed a bug that an internal do_insert_with_hash method gets the current Instant too early when eviction listener is enabled. (#322)

Version 0.11.3

Fixed

  • Fixed a bug in sync::Cache and sync::SegmentedCache where memory usage kept increasing when the eviction listener was set with the Immediate delivery mode. (#295)

Version 0.11.2

Bumped the minimum supported Rust version (MSRV) to 1.65 (Nov 3, 2022). (#275)

Removed

  • Removed num_cpus crate from the dependency. (#277)

Changed

  • Refactored internal methods of the concurrent hash table to reduce compile times. (#265, by @Swatinem)

Version 0.11.1

Fixed

  • Fixed occasional panic in internal FrequencySketch in debug build. (#272)

Added

Version 0.11.0

Added

  • Added support for per-entry expiration (#248):
    • In addition to the existing TTL and TTI (time-to-idle) expiration times that apply to all entries in the cache, the sync and future caches can now allow different expiration times for individual entries.
  • Added the remove method to the sync and future caches (#255):
    • Like the invalidate method, this method discards any cached value for the key, but returns a clone of the value.

Fixed

  • Fixed the caches mutating a deque node through a NonNull pointer derived from a shared reference. (#259)

Removed

  • Removed unsync cache that was marked as deprecated in v0.10.0.

Version 0.10.2

Bumped the minimum supported Rust version (MSRV) to 1.60 (Apr 7, 2022). (#252)

Changed

  • Upgraded quanta crate to v0.11.0. (#251)
    • This resolved "RUSTSEC-2020-0168: mach is unmaintained" (#243) by replacing mach with mach2.
    • quanta v0.11.0's MSRV is 1.60, so we also bumped the MSRV of Moka to 1.60.

Version 0.10.1

Fixed

  • Fixed a bug that future cache's blocking().invalidate(key) method does not trigger the eviction listener. (#242)

Changed

  • Now sync and future caches will not cache anything when the max capacity is set to zero (#230):
    • Previously, they would cache some entries for short time (< 0.5 secs) even though the max capacity is zero.

Version 0.10.0

Breaking Changes

  • The following caches have been moved to a separate crate called Mini-Moka:
    • moka::unsync::Cachemini_moka::unsync::Cache
    • moka::dash::Cachemini_moka::sync::Cache
  • The following methods have been removed from sync and future caches (#199). They were deprecated in v0.8.0:
    • get_or_insert_with (Use get_with instead)
    • get_or_try_insert_with (Use try_get_with instead)
  • The following methods of sync and future caches have been marked as deprecated (#193):
    • get_with_if (Use entry API's or_insert_with_if instead)

Added

  • Add entry and entry_by_ref APIs to sync and future caches (#193):
    • They allow users to perform more complex operations on a cache entry. At this point, the following operations (methods) are provided:
      • or_default
      • or_insert
      • or_insert_with
      • or_insert_with_if
      • or_optionally_insert_with
      • or_try_insert_with
    • The above methods return Entry type, which provides is_fresh method to check if the value was freshly computed or already existed in the cache.

Version 0.9.7

Fixed

  • Fix an issue that get_with method of future cache inflates future size by ~7x, sometimes causing stack overflow (#212):
    • This was caused by a known rustc optimization issue on async functions (rust-lang/rust#62958).
    • Added a workaround to our cache and now it will only inflate the size by ~2.5x.
  • Fix a bug that setting the number of segments of sync cache will disable notifications. (#207)

Added

  • Add examples for build_with_hasher method of cache builders. (#216)

Version 0.9.6

Fixed

  • Prevent race condition in get_with family methods to avoid evaluating init closure or future multiple times in concurrent calls. (#195)

Version 0.9.5

Added

  • Add optionally_get_with method to sync and future caches (#187, by @LMJW):
    • It is similar to try_get_with but takes an init closure/future returning an Option<V> instead of Result<V, E>.
  • Add by_ref version of API for get_with, optionally_get_with, and try_get_with of sync and future caches (#190, by @LMJW):
    • They are similar to the non-by_ref versions but take a reference of the key instead of an owned key. If the key does not exist in the cache, the key will be cloned to create new entry in the cache.

Changed

  • Change the CI to run Linux AArch64 tests on real hardware using Cirrus CI. (#180, by @ClSlaid)

Fixed

Version 0.9.4

Fixed

  • Fix memory leak after dropping a sync or future cache (#177):
    • This leaked the value part of cache entries.

Added

  • Add an experimental js feature to make unsync and sync caches to compile for wasm32-unknown-unknown target (#173, by @aspect):
    • Note that we have not tested if these caches work correctly in wasm32 environment.

Version 0.9.3

Added

  • Add an option to the cache builder of the following caches not to start and use the global thread pools for housekeeping tasks (#165):
    • sync::Cache
    • sync::SegmentedCache

Fixed

  • Ensure that the following caches will drop the value of evicted entries immediately after eviction (#169):
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache

Version 0.9.2

Fixed

  • Fix segmentation faults in sync and future caches under heavy loads on many-core machine (#34):
    • NOTE: Although this issue was found in our testing environment ten months ago (v0.5.1), no user reported that they had the same issue.
    • NOTE: In v0.8.4, we added a mitigation to reduce the chance of the segfaults occurring.

Changed

  • Upgrade crossbeam-epoch from v0.8.2 to v0.9.9 (#157):
    • This will make GitHub Dependabot to stop alerting about a security advisory CVE-2022-23639 for crossbeam-utils versions < 0.8.7.
    • Moka v0.9.1 or older was not vulnerable to the CVE:
      • Although the older crossbeam-epoch v0.8.2 depends on an affected version of crossbeam-utils, epoch v0.8.2 does not use the affected functions of utils. (#162)

Version 0.9.1

Fixed

  • Relax a too restrictive requirement Arc<K>: Borrow<Q> for the key &Q of the contains_key, get and invalidate methods in the following caches (with K as the key type) (#167). The requirement is now K: Borrow<Q> so these methods will accept &[u8] for the key &Q when the stored key K is Vec<u8>.
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache

Version 0.9.0

Added

  • Add support for eviction listener to the following caches (#145). Eviction listener is a callback function that will be called when an entry is removed from the cache:
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache
  • Add a crate feature sync for enabling and disabling sync caches. (#141 by @Milo123459, and #143)
    • This feature is enabled by default.
    • When using experimental dash cache, opting out of sync will reduce the number of dependencies.
  • Add a crate feature logging to enable optional log crate dependency. (#159)
    • Currently log will be emitted only when an eviction listener has panicked.

Version 0.8.6

Fixed

  • Fix a bug caused invalidate_all and invalidate_entries_if of the following caches will not invalidate entries inserted just before calling them (#155):
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache
    • Experimental dash::Cache

Version 0.8.5

Added

  • Add basic stats (entry_count and weighted_size) methods to all caches. (#137)
  • Add Debug impl to the following caches (#138):
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache
    • unsync::Cache

Fixed

  • Remove unnecessary K: Clone bound from the following caches when they are Clone (#133):
    • sync::Cache
    • future::Cache
    • Experimental dash::Cache

Version 0.8.4

Fixed

  • Fix the following issue by upgrading Quanta crate to v0.10.0 (#126):
    • Quanta v0.9.3 or older may not work correctly on some x86_64 machines where the Time Stamp Counter (TSC) is not synched across the processor cores. (#119)
    • For more details about the issue, see the relevant section of the README.

Added

  • Add get_with_if method to the following caches (#123):
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache

Changed

The followings are internal changes to improve memory safety in unsafe Rust usages in Moka:

  • Remove pointer-to-integer transmute by converting UnsafeWeakPointer from usize to *mut T. (#127, by saethlin)
  • Increase the num segments of the waiters hash table from 16 to 64 (#129) to reduce the chance of the following issue occurring:
    • Segfaults under heavy workloads on a many-core machine. (#34)

Version 0.8.3

Changed

  • Make Quanta crate optional (but enabled by default) (#121)
    • Quanta v0.9.3 or older may not work correctly on some x86_64 machines where the Time Stamp Counter (TSC) is not synched across the processor cores. (#119)
    • This issue was fixed by Quanta v0.10.0. You can prevent the issue by upgrading Moka to v0.8.4 or newer.
    • For more details about the issue, see the relevant section of the README.

Version 0.8.2

Added

  • Add iterator to the following caches: (#114)
    • sync::Cache
    • sync::SegmentedCache
    • future::Cache
    • unsync::Cache
  • Implement IntoIterator to the all caches (including experimental dash::Cache) (#114)

Fixed

  • Fix the dash::Cache iterator not to return expired entries. (#116)
  • Prevent "index out of bounds" error when sync::SegmentedCache was created with a non-power-of-two segments. (#117)

Version 0.8.1

Added

  • Add contains_key method to check if a key is present without resetting the idle timer or updating the historic popularity estimator. (#107)

Version 0.8.0

As a part of stabilizing the cache API, the following cache methods have been renamed:

  • get_or_insert_with(K, F)get_with(K, F)
  • get_or_try_insert_with(K, F)try_get_with(K, F)

Old methods are still available but marked as deprecated. They will be removed in a future version.

Also policy method was added to all caches and blocking method was added to future::Cache. They return a Policy struct or BlockingOp struct respectively. Some uncommon cache methods were moved to these structs, and old methods were removed without deprecating.

Please see #105 for the complete list of the affected methods.

Changed

  • API stabilization. (Smaller core cache API, shorter names for common methods) (#105)
  • Performance related:
    • Improve performance of get_with and try_get_with. (#88)
    • Avoid to calculate the same hash twice in get, get_with, insert, invalidate, etc. (#90)
  • Update the minimum versions of dependencies:
    • crossbeam-channel to v0.5.4. (#100)
    • scheduled-thread-pool to v0.2.5. (#103, by @Milo123459)
    • (dev-dependency) skeptic to v0.13.5. (#104)

Added

Experimental Additions

  • Add a synchronous cache moka::dash::Cache, which uses dashmap::DashMap as the internal storage. (#99)
  • Add iterator to moka::dash::Cache. (#101)

Please note that the above additions are highly experimental and their APIs will be frequently changed in next few releases.

Version 0.7.2

The minimum supported Rust version (MSRV) is now 1.51.0 (Mar 25, 2021).

Fixed

  • Addressed a memory utilization issue that will get worse when keys have hight cardinality (#72):
    • Reduce memory overhead in the internal concurrent hash table (cht). (#79)
    • Fix a bug that can create oversized frequency sketch when weigher is set. (#75)
    • Change EntryInfo from enum to struct to reduce memory utilization. (#76)
    • Replace some std::sync::Arc usages with triomphe::Arc to reduce memory utilization. (#80)
    • Embed CacheRegion value into a 2-bit tag space of TagNonNull pointer. (#84)
  • Fix a bug that will use wrong (oversized) initial capacity for the internal cht. (#83)

Added

  • Add unstable-debug-counters feature for testing purpose. (#82)

Changed

  • Import (include) cht source files for better integration. (#77, #86)
  • Improve the CI coverage for Clippy lints and fix some Clippy warnings in unit tests. (#73, by @06chaynes)

Version 0.7.1

  • Important Fix: A memory leak issue (#65 below) was found in all previous versions (since v0.1.0) and fixed in this version. All users are encouraged to upgrade to this or newer version.

Fixed

  • Fix a memory leak that will happen when evicting/expiring an entry or manually invalidating an entry. (#65)

Changed

  • Update the minimum depending version of crossbeam-channel from v0.5.0 to v0.5.2. (#67)

Version 0.7.0

  • Breaking change: The type of the max_capacity has been changed from usize to u64. This was necessary to have the weight-based cache management consistent across different CPU architectures.

Added

  • Add support for weight-based (size aware) cache management. (#24)
  • Add support for unbound cache. (#24)

Version 0.6.3

Fixed

  • Fix a bug in get_or_insert_with and get_or_try_insert_with methods of future::Cache, which caused a panic if previously inserting task aborted. (#59)

Version 0.6.2

Removed

  • Remove Send and 'static bounds from get_or_insert_with and get_or_try_insert_with methods of future::Cache. (#53, by @tinou98)

Fixed

  • Protect overflow when computing expiration. (#56, by @barkanido)

Version 0.6.1

Changed

  • Replace futures crate with futures-util. (#47, by @messense))

Version 0.6.0

Fixed

  • Fix a bug in get_or_insert_with and get_or_try_insert_with methods of future::Cache and sync::Cache; a panic in the init future/closure causes subsequent calls on the same key to get "unreachable code" panics. (#43)

Changed

  • Change get_or_try_insert_with to return a concrete error type rather than a trait object. (#23, #37)

Version 0.5.4

Changed

  • Restore quanta dependency on some 32-bit platforms such as armv5te-unknown-linux-musleabi or mips-unknown-linux-musl. (#42, by @messense)

Version 0.5.3

Added

  • Add support for some 32-bit platforms where std::sync::atomic::AtomicU64 is not provided. (e.g. armv5te-unknown-linux-musleabi or mips-unknown-linux-musl) (#38)
    • On these platforms, you will need to disable the default features of Moka. See the relevant section of the README.

Version 0.5.2

Fixed

  • Fix a bug in get_or_insert_with and get_or_try_insert_with methods of future::Cache by adding missing bounds Send and 'static to the init future. Without this fix, these methods will accept non-Send or non-'static future and may cause undefined behavior. (#31)
  • Fix usize overflow on big cache capacity. (#28)

Added

  • Add examples for get_or_insert_with and get_or_try_insert_with methods to the docs. (#30)

Changed

  • Downgrade crossbeam-epoch used in moka-cht from v0.9.x to v0.8.x as a possible workaround for segmentation faults on many-core CPU machines. (#33)

Version 0.5.1

Changed

  • Replace a dependency cht v0.4 with moka-cht v0.5. (#22)

Version 0.5.0

Added

  • Add get_or_insert_with and get_or_try_insert_with methods to sync and future caches. (#20)

Version 0.4.0

Fixed

  • Breaking change: Now sync::{Cache, SegmentedCache} and future::Cache require Send, Sync and 'static for the generic parameters K (key), V (value) and S (hasher state). This is necessary to prevent potential undefined behaviors in applications using single-threaded async runtime such as Actix-rt. (#19)

Added

  • Add invalidate_entries_if method to sync, future and unsync caches. (#12)

Version 0.3.1

Changed

  • Stop skeptic from having to be compiled by all downstream users. (#16, by @paolobarbolini)

Version 0.3.0

Added

  • Add an unsync cache (moka::unsync::Cache) and its builder for single-thread applications. (#9)
  • Add invalidate_all method to sync, future and unsync caches. (#11)

Fixed

  • Fix problems including segfault caused by race conditions between the sync/eviction thread and client writes. (Addressed as a part of #11).

Version 0.2.0

Added

  • Add an asynchronous, futures aware cache (moka::future::Cache) and its builder. (#7)

Version 0.1.0

Added

  • Add thread-safe, highly concurrent in-memory cache implementations (moka::sync::{Cache, SegmentedCache}) with the following features:
    • Bounded by the maximum number of elements.
    • Maintains good hit rate by using entry replacement algorithms inspired by Caffeine:
      • Admission to a cache is controlled by the Least Frequently Used (LFU) policy.
      • Eviction from a cache is controlled by the Least Recently Used (LRU) policy.
    • Expiration policies:
      • Time to live
      • Time to idle