Commit e8302a45 authored by Emmanuel Bourg's avatar Emmanuel Bourg

Merge tag 'upstream/2.6.2'

Upstream version 2.6.2
parents 98d5c5e9 e58a53ba
* text=auto
gradlew text eol=lf
gradlew.bat text eol=crlf
bin
build
test-output
jitwatch.out
.java-version
.DS_Store
.classpath
.settings
.project
.gradle
.idea
*.iml
target
**/hs_err_pid*.log
**/replay_pid*.log
**/caffeine.log
To get started, [sign the Contributor License Agreement](https://www.clahub.com/agreements/ben-manes/caffeine).
Then head over to [How to Contribute](https://github.com/ben-manes/caffeine/wiki/Contribute)
for details on the build system.
This diff is collapsed.
[![Build Status](https://travis-ci.org/ben-manes/caffeine.svg)](https://travis-ci.org/ben-manes/caffeine)
[![Coverage Status](https://img.shields.io/coveralls/ben-manes/caffeine.svg)](https://coveralls.io/r/ben-manes/caffeine?branch=master)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.ben-manes.caffeine/caffeine/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.ben-manes.caffeine/caffeine)
[![JavaDoc](http://www.javadoc.io/badge/com.github.ben-manes.caffeine/caffeine.svg)](http://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine)
[![License](http://img.shields.io/:license-apache-brightgreen.svg)](http://www.apache.org/licenses/LICENSE-2.0.html)
[![Stack Overflow](http://img.shields.io/:stack%20overflow-caffeine-brightgreen.svg)](http://stackoverflow.com/questions/tagged/caffeine)
<a href="https://github.com/ben-manes/caffeine/wiki">
<img align="right" height="90px" src="https://raw.githubusercontent.com/ben-manes/caffeine/master/wiki/logo.png">
</a>
Caffeine is a [high performance][benchmarks], [near optimal][efficiency] caching library based on
Java 8. For more details, see our [user's guide][users-guide] and browse the [API docs][javadoc] for
the latest release.
### Cache
Caffeine provides an in-memory cache using a Google Guava inspired API. The improvements draw on our
experience designing [Guava's cache][guava-cache] and [ConcurrentLinkedHashMap][clhm].
```java
LoadingCache<Key, Graph> graphs = Caffeine.newBuilder()
.maximumSize(10_000)
.expireAfterWrite(5, TimeUnit.MINUTES)
.refreshAfterWrite(1, TimeUnit.MINUTES)
.build(key -> createExpensiveGraph(key));
```
#### Features at a Glance
Caffeine provides flexible construction to create a cache with a combination of the following features:
* [automatic loading of entries][population] into the cache, optionally asynchronously
* [size-based eviction][size] when a maximum is exceeded based on [frequency and recency][efficiency]
* [time-based expiration][time] of entries, measured since last access or last write
* [asynchronously refresh][refresh] when the first stale request for an entry occurs
* keys automatically wrapped in [weak references][reference]
* values automatically wrapped in [weak or soft references][reference]
* [notification][listener] of evicted (or otherwise removed) entries
* [writes propagated][writer] to an external resource
* accumulation of cache access [statistics][statistics]
In addition, Caffeine offers the following extensions:
* [JSR-107 JCache][jsr107]
* [Guava adapters][guava-adapter]
* [Simulation][simulator]
Use Caffeine in a community provided integration:
* [Spring Cache][spring]: As of Spring 4.3 & Boot 1.4
* [Scaffeine][scaffeine]: Scala wrapper for Caffeine
* [ScalaCache][scala-cache]: Simple caching in Scala
* [Camel][camel]: Routing and mediation engine
* [jooby][jooby]: Modular micro framework
* [Druid][druid]: Real-time analytics
Powering infrastructure near you:
* [Cassandra][cassandra]: Manage massive amounts of data, fast
* [Infinispan][infinispan]: Distributed in-memory data grid
* [Akka][akka-http]: Build reactive applications easily
* [Ratpack][ratpack]: Lean & powerful HTTP apps
* [Corfu][corfu]: A cluster consistency platform
* [Orbit][orbit]: Virtual actors on the JVM
* [Finagle][finagle]: Extensible RPC system
* [Neo4j][neo4j]: Graphs for Everyone
### In the News
* A short look at what Caffeine brings to your applications.
* [Add a Boost of Caffeine to Your Java][add-a-boost] at [VOXXED][voxxed]
* An in-depth description of Caffeine's architecture.
* [Design of a Modern Cache][modern-cache] ([slides][modern-cache-slides]) at [HighScalability][HighScalability]
* Caffeine is presented as part of a research paper evaluating its novel eviction policy.
* [TinyLFU: A Highly Efficient Cache Admission Policy][tinylfu] by Gil Einziger, Roy Friedman, Ben Manes
On the radar,
* Early discussions with [HBase][hbase], [Solr][solr], and [Play!][play]
* W-TinyLfu implemented by [go-tinylfu][go-tinylfu], [mango-cache][mango-cache], [transitory][transitory], and [ohc][ohc]
### Download
Download from [Maven Central][maven] or depend via Gradle:
```gradle
compile 'com.github.ben-manes.caffeine:caffeine:2.6.1'
// Optional extensions
compile 'com.github.ben-manes.caffeine:guava:2.6.1'
compile 'com.github.ben-manes.caffeine:jcache:2.6.1'
```
See the [release notes][releases] for details of the changes.
Snapshots of the development version are available in
[Sonatype's snapshots repository][snapshots].
[benchmarks]: https://github.com/ben-manes/caffeine/wiki/Benchmarks
[users-guide]: https://github.com/ben-manes/caffeine/wiki
[javadoc]: http://www.javadoc.io/doc/com.github.ben-manes.caffeine/caffeine
[guava-cache]: https://github.com/google/guava/wiki/CachesExplained
[clhm]: https://code.google.com/p/concurrentlinkedhashmap
[population]: https://github.com/ben-manes/caffeine/wiki/Population
[size]: https://github.com/ben-manes/caffeine/wiki/Eviction#size-based
[time]: https://github.com/ben-manes/caffeine/wiki/Eviction#time-based
[refresh]: https://github.com/ben-manes/caffeine/wiki/Refresh
[reference]: https://github.com/ben-manes/caffeine/wiki/Eviction#reference-based
[listener]: https://github.com/ben-manes/caffeine/wiki/Removal
[writer]: https://github.com/ben-manes/caffeine/wiki/Writer
[statistics]: https://github.com/ben-manes/caffeine/wiki/Statistics
[simulator]: https://github.com/ben-manes/caffeine/wiki/Simulator
[guava-adapter]: https://github.com/ben-manes/caffeine/wiki/Guava
[jsr107]: https://github.com/ben-manes/caffeine/wiki/JCache
[maven]: https://maven-badges.herokuapp.com/maven-central/com.github.ben-manes.caffeine/caffeine
[releases]: https://github.com/ben-manes/caffeine/releases
[snapshots]: https://oss.sonatype.org/content/repositories/snapshots
[efficiency]: https://github.com/ben-manes/caffeine/wiki/Efficiency
[tinylfu]: https://dl.acm.org/authorize?N41277
[add-a-boost]: https://www.voxxed.com/blog/2015/12/add-a-boost-of-caffeine-to-your-java
[voxxed]: https://www.voxxed.com
[modern-cache]: http://highscalability.com/blog/2016/1/25/design-of-a-modern-cache.html
[modern-cache-slides]: https://docs.google.com/presentation/d/1NlDxyXsUG1qlVHMl4vsUUBQfAJ2c2NsFPNPr2qymIBs
[highscalability]: http://highscalability.com
[spring]: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html#cache-store-configuration-caffeine
[scala-cache]: https://github.com/cb372/scalacache
[scaffeine]: https://github.com/blemale/scaffeine
[hbase]: https://issues.apache.org/jira/browse/HBASE-15560
[cassandra]: http://cassandra.apache.org
[solr]: https://issues.apache.org/jira/browse/SOLR-8241
[infinispan]: http://infinispan.org/docs/stable/user_guide/user_guide.html#eviction_strategy
[neo4j]: https://github.com/neo4j/neo4j
[ohc]: https://github.com/snazy/ohc
[go-tinylfu]: https://github.com/dgryski/go-tinylfu
[mango-cache]: https://github.com/goburrow/cache
[transitory]: https://github.com/aholstenson/transitory
[ratpack]: https://github.com/ratpack/ratpack
[finagle]: https://github.com/twitter/finagle
[druid]: http://druid.io/docs/latest/development/extensions-core/caffeine-cache.html
[jooby]: http://jooby.org/doc/caffeine
[orbit]: https://github.com/orbit/orbit
[camel]: https://github.com/apache/camel/blob/master/components/camel-caffeine/src/main/docs/caffeine-cache-component.adoc
[corfu]: https://github.com/CorfuDB/CorfuDB
[akka-http]: https://doc.akka.io/docs/akka-http/current/common/caching.html
[play]: https://github.com/playframework/playframework/pull/8025
apply plugin: 'com.gradle.build-scan'
apply plugin: me.champeau.gradle.buildscans.RecipesPlugin
apply plugin: 'com.github.mjdetullio.gradle.coverity'
apply plugin: 'com.github.ben-manes.versions'
apply plugin: 'com.github.kt3k.coveralls'
apply plugin: 'jacoco'
buildscript {
apply from: "${rootDir}/gradle/dependencies.gradle"
repositories {
maven { url "http://repo.spring.io/plugins-release" }
gradlePluginPortal()
mavenCentral()
jcenter()
}
dependencies {
classpath gradlePlugins.values()
}
}
buildScan {
licenseAgree = 'yes'
licenseAgreementUrl = 'https://gradle.com/terms-of-service'
}
buildScanRecipes {
recipes 'git-status', 'travis-ci', 'disk-usage', 'gc-stats'
recipe 'git-commit', baseUrl: 'https://github.com/ben-manes/caffeine/tree'
}
task testReport(type: TestReport, group: 'Build') {
description = 'Generates an aggregate test report'
destinationDir = file("${buildDir}/reports/allTests")
}
allprojects {
apply from: "${rootDir}/gradle/eclipse.gradle"
repositories {
jcenter()
mavenCentral()
maven { url 'https://jitpack.io' }
}
}
subprojects {
apply plugin: 'com.github.ethankhall.semantic-versioning'
apply plugin: 'net.ltgt.errorprone'
apply plugin: 'propdeps-maven'
apply plugin: 'eclipse'
apply plugin: 'java'
apply plugin: 'idea'
apply plugin: 'osgi'
apply from: "${rootDir}/gradle/publish.gradle"
apply from: "${rootDir}/gradle/codeQuality.gradle"
apply from: "${rootDir}/gradle/dependencies.gradle"
apply from: "${rootDir}/gradle/objectLayout.gradle"
if (JavaVersion.current().isJava9Compatible()) {
tasks.uploadArchives.enabled = false
}
sourceCompatibility = JavaVersion.VERSION_1_8
group = 'com.github.ben-manes.caffeine'
version.with {
major = 2 // incompatible API changes
minor = 6 // backwards-compatible additions
patch = 2 // backwards-compatible bug fixes
releaseBuild = rootProject.hasProperty('release')
}
archivesBaseName = path[1..-1].replaceAll(':', '-').toLowerCase()
idea.module {
scopes.PROVIDED.plus += [ configurations.provided ]
}
dependencies {
provided libraries.jsr305
provided libraries.errorProneAnnotations
testCompile libraries.guava
testCompile testLibraries.mockito
testCompile testLibraries.hamcrest
testCompile testLibraries.awaitility
testCompile testLibraries.osgiCompile
testRuntime testLibraries.osgiRuntime
}
configurations {
testArtifacts
}
tasks.withType(Test) {
if (!it.name.startsWith('slow')) {
rootProject.testReport.reportOn it
}
it.dependsOn('jar')
// ensure tasks don't overwrite the default report directories used by the 'test' task
reports.html.destination = file("${buildDir}/reports/${name}")
reports.junitXml.destination = file("${buildDir}/reports/${name}/results")
binResultsDir = file("${buildDir}/reports/${name}/results/binary/${name}")
}
task testJar(type: Jar, group: 'Build') {
description = 'Assembles a jar archive containing the test classes.'
baseName = "${archivesBaseName}-test"
from sourceSets.test.output
}
artifacts {
testArtifacts testJar
}
if (project != project(':caffeine')) {
javadoc.options.linksOffline(
"https://static.javadoc.io/${group}/caffeine/${version}/",
"${project(':caffeine').buildDir}/docs/javadoc/",
)
javadoc.dependsOn(project(':caffeine').javadoc)
}
}
// Only report code coverage for projects that are distributed
def publishedProjects = subprojects.findAll { it.path != ':simulator' }
task jacocoMerge(type: JacocoMerge) {
publishedProjects.each { subproject ->
executionData subproject.tasks.withType(Test)
}
doFirst {
executionData = files(executionData.findAll { it.exists() })
}
}
task jacocoRootReport(type: JacocoReport, group: 'Coverage reports') {
description = 'Generates an aggregate report from all subprojects'
dependsOn publishedProjects.test, jacocoMerge
additionalSourceDirs = files(publishedProjects.sourceSets.main.allSource.srcDirs)
sourceDirectories = files(publishedProjects.sourceSets.main.allSource.srcDirs)
classDirectories = files(publishedProjects.sourceSets.main.output)
executionData jacocoMerge.destinationFile
reports {
html.enabled = true // human readable
xml.enabled = true // required by coveralls
}
}
coveralls {
sourceDirs = publishedProjects.sourceSets.main.allSource.srcDirs.flatten()
jacocoReportPath = "${buildDir}/reports/jacoco/jacocoRootReport/jacocoRootReport.xml"
}
tasks.coveralls {
group = 'Coverage reports'
description = 'Uploads the aggregated coverage report to Coveralls'
dependsOn jacocoRootReport
onlyIf { System.env.'CI' && !JavaVersion.current().isJava9Compatible() }
}
apply from: "${rootDir}/gradle/jmh.gradle"
apply from: "${projectDir}/testing.gradle"
sourceSets {
javaPoet {
java.srcDir 'src/javaPoet/java'
}
main {
java.srcDir "${buildDir}/generated-sources/"
}
codeGen {
java.srcDir "${buildDir}/generated-sources/"
}
}
configurations {
javaAgent
}
idea.module {
scopes.PROVIDED.plus += [ configurations.javaPoetCompile ]
}
plugins.withType(EclipsePlugin) {
project.eclipse.classpath.plusConfigurations += [ configurations.javaPoetCompile ]
}
dependencies {
testCompile libraries.ycsb
testCompile libraries.guava
testCompile libraries.fastutil
testCompile testLibraries.junit
testCompile testLibraries.testng
testCompile testLibraries.jctools
testCompile libraries.commonsLang3
testCompile testLibraries.guavaTestLib
javaAgent benchmarkLibraries.jamm
jmh libraries.flipTables
jmh benchmarkLibraries.jamm
jmh benchmarkLibraries.tcache
jmh benchmarkLibraries.cache2k
jmh benchmarkLibraries.ehcache2
jmh benchmarkLibraries.ehcache3
jmh benchmarkLibraries.koloboke
jmh benchmarkLibraries.rapidoid
jmh benchmarkLibraries.slf4jNop
jmh benchmarkLibraries.collision
jmh benchmarkLibraries.jackrabbit
jmh benchmarkLibraries.expiringMap
jmh benchmarkLibraries.elasticSearch
jmh benchmarkLibraries.concurrentlinkedhashmap
javaPoetCompile libraries.guava
javaPoetCompile libraries.jsr305
javaPoetCompile libraries.javapoet
javaPoetCompile libraries.commonsLang3
}
compileCodeGenJava {
outputs.upToDateWhen {
!gradle.taskGraph.hasTask('uploadArchives')
}
dependsOn compileJava
destinationDir = compileJava.destinationDir
classpath = sourceSets.main.runtimeClasspath + sourceSets.main.output
options.incremental = false
options.debug = false
}
jar.manifest {
name 'com.github.ben-manes.caffeine'
instruction 'Import-Package',
'sun.misc.*;resolution:=optional'
instruction 'Export-Package',
'com.github.benmanes.caffeine',
'com.github.benmanes.caffeine.base',
'com.github.benmanes.caffeine.cache',
'com.github.benmanes.caffeine.cache.stats'
instruction 'Automatic-Module-Name',
'com.github.benmanes.caffeine'
}
jar.dependsOn(compileCodeGenJava)
sonarqube {
properties {
property "sonar.exclusions", '**/NodeFactory.java, **/LocalCacheFactory.java'
}
}
task generateLocalCaches(type: JavaExec) {
main = 'com.github.benmanes.caffeine.cache.LocalCacheFactoryGenerator'
classpath = sourceSets.javaPoet.runtimeClasspath
args "${buildDir}/generated-sources/"
jvmArgs += '-noverify'
outputs.upToDateWhen { !tasks.compileJavaPoetJava.didWork }
}
compileJava.dependsOn(generateLocalCaches)
task generateNodes(type: JavaExec) {
main = 'com.github.benmanes.caffeine.cache.NodeFactoryGenerator'
classpath = sourceSets.javaPoet.runtimeClasspath
args "${buildDir}/generated-sources/"
jvmArgs += '-noverify'
outputs.upToDateWhen { !tasks.compileJavaPoetJava.didWork }
}
compileJava.dependsOn(generateNodes)
task memoryOverhead(type: JavaExec, group: 'Benchmarks', description: 'Evaluates cache overhead') {
classpath sourceSets.jmh.runtimeClasspath
jvmArgs "-javaagent:${configurations.javaAgent.singleFile}"
main = 'com.github.benmanes.caffeine.cache.MemoryBenchmark'
}
/*
* Copyright 2015 Ben Manes. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.benmanes.caffeine.cache;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Sets;
/**
* The features that may be code generated.
*
* @author ben.manes@gmail.com (Ben Manes)
*/
public enum Feature {
STRONG_KEYS,
WEAK_KEYS,
STRONG_VALUES,
INFIRM_VALUES,
WEAK_VALUES,
SOFT_VALUES,
EXPIRE_ACCESS,
EXPIRE_WRITE,
REFRESH_WRITE,
MAXIMUM_SIZE,
MAXIMUM_WEIGHT,
LISTENING,
STATS;
public static String makeEnumName(Iterable<Feature> features) {
return StreamSupport.stream(features.spliterator(), false)
.map(Feature::name)
.collect(Collectors.joining("_"));
}
public static String makeEnumName(String enumName) {
return CaseFormat.UPPER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, enumName);
}
public static String makeClassName(Iterable<Feature> features) {
String enumName = makeEnumName(features);
return makeClassName(enumName);
}