Add 'missing' parameter to get()

This commit is contained in:
Winston Chang
2018-06-29 13:23:47 -05:00
parent fe6ad235ac
commit d1f20a9c73
6 changed files with 62 additions and 42 deletions

View File

@@ -18,6 +18,11 @@
#' return a different sentinel value, like \code{NULL}, or even throw an error
#' on a cache miss.
#'
#' When the cache is created, you can supply a value for \code{missing}, which
#' sets the default value to be returned for missing values. It can also be
#' overridden when \code{get()} is called, by supplying a \code{missing}
#' argument, as in \code{cache$get("mykey", missing = NULL)}.
#'
#' If your cache is configured so that \code{get()} returns a sentinel value
#' to represent a cache miss, then \code{set} will also not allow you to store
#' the sentinel value in the cache. It will throw an error if you attempt to
@@ -106,9 +111,11 @@
#' A disk cache object has the following methods:
#'
#' \describe{
#' \item{\code{get(key)}}{
#' \item{\code{get(key, missing)}}{
#' Returns the value associated with \code{key}. If the key is not in the
#' cache, this throws an error.
#' cache, then it returns the value specified by \code{missing}. The
#' default value for \code{missing} when the DiskCache object is created,
#' but it can be overridden when \code{get()} is called.
#' }
#' \item{\code{set(key, value)}}{
#' Stores the \code{key}-\code{value} pair in the cache.
@@ -218,10 +225,9 @@ DiskCache <- R6Class("DiskCache",
private$evict <- "fifo"
}
private$missing <- missing
private$eval_missing <- is.language(missing)
},
get = function(key) {
get = function(key, missing = private$missing) {
self$is_destroyed(throw = TRUE)
validate_key(key)
filename <- private$key_to_filename(key)
@@ -239,10 +245,10 @@ DiskCache <- R6Class("DiskCache",
}
)
if (read_error) {
if (private$eval_missing) {
return(eval(private$missing))
if (is.language(missing)) {
return(eval(missing))
} else {
return(private$missing)
return(missing)
}
}
@@ -253,7 +259,7 @@ DiskCache <- R6Class("DiskCache",
set = function(key, value) {
self$is_destroyed(throw = TRUE)
validate_key(key)
if (!private$eval_missing && identical(value, private$missing)) {
if (!is.language(private$missing) && identical(value, private$missing)) {
stop("Attempted to store sentinel value representing a missing key.")
}
@@ -427,7 +433,6 @@ DiskCache <- R6Class("DiskCache",
destroy_on_finalize = NULL,
destroyed = FALSE,
missing = NULL,
eval_missing = NULL,
key_to_filename = function(key) {
if (! (is.character(key) && length(key)==1) ) {

View File

@@ -25,6 +25,11 @@
#' return a different sentinel value, like \code{NULL}, or even throw an error
#' on a cache miss.
#'
#' When the cache is created, you can supply a value for \code{missing}, which
#' sets the default value to be returned for missing values. It can also be
#' overridden when \code{get()} is called, by supplying a \code{missing}
#' argument, as in \code{cache$get("mykey", missing = NULL)}.
#'
#' If your cache is configured so that \code{get()} returns a sentinel value
#' to represent a cache miss, then \code{set} will also not allow you to store
#' the sentinel value in the cache. It will throw an error if you attempt to
@@ -88,9 +93,11 @@
#' A disk cache object has the following methods:
#'
#' \describe{
#' \item{\code{get(key)}}{
#' \item{\code{get(key, missing)}}{
#' Returns the value associated with \code{key}. If the key is not in the
#' cache, this throws an error.
#' cache, then it returns the value specified by \code{missing}. The
#' default value for \code{missing} when the DiskCache object is created,
#' but it can be overridden when \code{get()} is called.
#' }
#' \item{\code{set(key, value)}}{
#' Stores the \code{key}-\code{value} pair in the cache.
@@ -146,16 +153,15 @@ MemoryCache <- R6Class("MemoryCache",
private$max_n <- max_n
private$evict <- match.arg(evict)
private$missing <- missing
private$eval_missing <- is.language(missing)
},
get = function(key) {
get = function(key, missing = private$missing) {
validate_key(key)
if (!self$exists(key)) {
if (private$eval_missing) {
return(eval(private$missing))
if (is.language(missing)) {
return(eval(missing))
} else {
return(private$missing)
return(missing)
}
}
@@ -166,7 +172,7 @@ MemoryCache <- R6Class("MemoryCache",
set = function(key, value) {
validate_key(key)
if (!private$eval_missing && identical(value, private$missing)) {
if (!is.language(private$missing) && identical(value, private$missing)) {
stop("Attempted to store sentinel value representing a missing key.")
}
@@ -275,7 +281,6 @@ MemoryCache <- R6Class("MemoryCache",
max_n = NULL,
evict = NULL,
missing = NULL,
eval_missing = NULL,
object_info = function() {
keys <- ls(private$cache, sorted = FALSE)

View File

@@ -286,19 +286,9 @@ renderCachedPlot <- function(expr,
key <- digest::digest(list(outputName, cacheKeyResult, width, height, res, pixelratio), "sha256")
cached_value <- cache$get(key)
# Get the key. Instead of using exists() before get(), try to simply
# get() the key and catch the exception if it fails. This is to avoid
# possible race conditions between calls to exists() and get()
get_value_failed <- FALSE
tryCatch(
cached_value <- cache$get(key),
error = function(e) {
get_value_failed <<- TRUE
}
)
if (!get_value_failed) {
if (!is.key_missing(cached_value)) {
cat("drawReactive(): cached\n")
# This will NOT include the displaylist.
return(cached_value)
@@ -399,15 +389,9 @@ renderCachedPlot <- function(expr,
key <- digest::digest(list(outputName, cacheKeyResult, width, height, res, pixelratio), "sha256")
get_value_failed <- FALSE
tryCatch(
cached_value <- cache$get(key),
error = function(e) {
get_value_failed <<- TRUE
}
)
cached_value <- cache$get(key)
if (!get_value_failed) {
if (!is.key_missing(cached_value)) {
cat("drawReactive(): cached\n")
result <- cached_value

View File

@@ -65,6 +65,11 @@ and \code{evict}.
return a different sentinel value, like \code{NULL}, or even throw an error
on a cache miss.
When the cache is created, you can supply a value for \code{missing}, which
sets the default value to be returned for missing values. It can also be
overridden when \code{get()} is called, by supplying a \code{missing}
argument, as in \code{cache$get("mykey", missing = NULL)}.
If your cache is configured so that \code{get()} returns a sentinel value
to represent a cache miss, then \code{set} will also not allow you to store
the sentinel value in the cache. It will throw an error if you attempt to
@@ -158,9 +163,11 @@ already been deleted.
A disk cache object has the following methods:
\describe{
\item{\code{get(key)}}{
\item{\code{get(key, missing)}}{
Returns the value associated with \code{key}. If the key is not in the
cache, this throws an error.
cache, then it returns the value specified by \code{missing}. The
default value for \code{missing} when the DiskCache object is created,
but it can be overridden when \code{get()} is called.
}
\item{\code{set(key, value)}}{
Stores the \code{key}-\code{value} pair in the cache.

View File

@@ -55,6 +55,11 @@ MemoryCache, it will not be garbage collected.
return a different sentinel value, like \code{NULL}, or even throw an error
on a cache miss.
When the cache is created, you can supply a value for \code{missing}, which
sets the default value to be returned for missing values. It can also be
overridden when \code{get()} is called, by supplying a \code{missing}
argument, as in \code{cache$get("mykey", missing = NULL)}.
If your cache is configured so that \code{get()} returns a sentinel value
to represent a cache miss, then \code{set} will also not allow you to store
the sentinel value in the cache. It will throw an error if you attempt to
@@ -124,9 +129,11 @@ policies are:
A disk cache object has the following methods:
\describe{
\item{\code{get(key)}}{
\item{\code{get(key, missing)}}{
Returns the value associated with \code{key}. If the key is not in the
cache, this throws an error.
cache, then it returns the value specified by \code{missing}. The
default value for \code{missing} when the DiskCache object is created,
but it can be overridden when \code{get()} is called.
}
\item{\code{set(key, value)}}{
Stores the \code{key}-\code{value} pair in the cache.

View File

@@ -7,6 +7,8 @@ test_that("DiskCache: handling missing values", {
expect_error(d$set("x", key_missing()))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = NULL), NULL)
expect_error(d$get("y", missing = quote(stop("Missing key"))), "^Missing key$")
d <- diskCache(missing = NULL)
expect_true(is.null(d$get("abcd")))
@@ -14,6 +16,8 @@ test_that("DiskCache: handling missing values", {
expect_error(d$set("x", NULL))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = -1), -1)
expect_error(d$get("y", missing = quote(stop("Missing key"))), "^Missing key$")
d <- diskCache(missing = quote(stop("Missing key")))
expect_error(d$get("abcd"), "^Missing key$")
@@ -23,6 +27,8 @@ test_that("DiskCache: handling missing values", {
expect_identical(d$get("x"), quote(stop("Missing key")))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = NULL), NULL)
expect_error(d$get("y", missing = quote(stop("Missing key 1"))), "^Missing key 1$")
})
test_that("MemoryCache: handling missing values", {
@@ -32,6 +38,8 @@ test_that("MemoryCache: handling missing values", {
expect_error(d$set("x", key_missing()))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = NULL), NULL)
expect_error(d$get("y", missing = quote(stop("Missing key"))), "^Missing key$")
d <- memoryCache(missing = NULL)
expect_true(is.null(d$get("abcd")))
@@ -39,6 +47,8 @@ test_that("MemoryCache: handling missing values", {
expect_error(d$set("x", NULL))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = -1), -1)
expect_error(d$get("y", missing = quote(stop("Missing key"))), "^Missing key$")
d <- memoryCache(missing = quote(stop("Missing key")))
expect_error(d$get("abcd"), "^Missing key$")
@@ -48,4 +58,6 @@ test_that("MemoryCache: handling missing values", {
expect_identical(d$get("x"), quote(stop("Missing key")))
d$set("a", 100)
expect_identical(d$get("a"), 100)
expect_identical(d$get("y", missing = NULL), NULL)
expect_error(d$get("y", missing = quote(stop("Missing key 1"))), "^Missing key 1$")
})