Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
fb271f1
Add google datastore memoization option.
danielecook Jul 25, 2016
e3569a6
add error messages and compression.
danielecook Jul 25, 2016
51a4544
Add to do and additional cache types.
danielecook Jul 25, 2016
56a6c8f
update readme.
danielecook Jul 25, 2016
1e8e809
Rewrite to use googleauthR
danielecook Jul 25, 2016
514514a
Fix cache return value and don't automatically reset cache.
danielecook Jul 25, 2016
20ce739
Finish datastore cache.
danielecook Jul 25, 2016
2e690c6
cleanup namespace
danielecook Jul 25, 2016
fc44834
Add AWS Service
danielecook Jul 25, 2016
0448ff8
Cleanup and readme.
danielecook Jul 25, 2016
9e1ac4c
Update README.md
danielecook Jul 25, 2016
27fe9e8
Rename, update
danielecook Jul 26, 2016
c2f0bce
Update description.
danielecook Jul 26, 2016
6fad8e3
fix description
danielecook Jul 26, 2016
73c11b4
fix remotes
danielecook Jul 26, 2016
cd16c33
fix remotes.
danielecook Jul 26, 2016
df3b92f
fix remotes.
danielecook Jul 26, 2016
4c6df0d
use git repo instead
danielecook Jul 26, 2016
25cbe38
Remotes were fine...
danielecook Jul 26, 2016
68e8636
Update README.md
danielecook Jul 27, 2016
f435e95
Restructure for fork
danielecook Jul 28, 2016
a952d5d
Merge branch 'master' of https://github.com/danielecook/xmemoise
danielecook Jul 28, 2016
c32fd35
Improve documentation.
danielecook Jul 28, 2016
324e5a5
remove documentation items not allowed...
danielecook Jul 28, 2016
9f4a914
Fixed final warnings.
danielecook Jul 28, 2016
5b3e9ee
improve documentation with examples.
danielecook Jul 29, 2016
f60558d
Update README.md
danielecook Jul 29, 2016
f6ddf99
Update README.md
danielecook Jul 31, 2016
d86494d
Update README.md
danielecook Jul 31, 2016
baed71c
Update README.md
danielecook Jul 31, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
^\.Rproj\.user$
^revdep$
^cran-comments\.md$
^\.httr-oauth$
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.Rproj.user
.Rhistory
.RData
.httr-oauth
19 changes: 14 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,18 +1,27 @@
Encoding: UTF-8
Package: memoise
Title: Memoisation of Functions
Version: 1.0.0.9000
Description: Memoisation allows the results of functions to be cached based on input parameters
xmemoise offers both local and remote caches, enabling memoisation across computers.
Additional cache types include google datastore and amazon aws.
Version: 1.0.1
Authors@R: c(
person("Hadley", "Wickham", , "[email protected]", role = "aut"),
person("Jim", "Hester", , "[email protected]", role = c("aut", "cre")),
person("Kirill", "Müller", , "[email protected]", role = "aut"))
person("Kirill", "Müller", , "[email protected]", role = "aut"),
person("Daniel", "Cook", , "[email protected]", role = "aut"))
Description: Cache the results of a function so that when you call it
again with the same arguments it returns the pre-computed value.
URL: https://github.com/hadley/memoise
URL: https://github.com/danielecook/xmemoise
BugReports: https://github.com/hadley/memoise/issues
Imports:
digest (>= 0.6.3)
digest (>= 0.6.3),
base64enc
Suggests:
testthat
testthat,
googleAuthR,
aws.s3
Remotes:
cloudyr/aws.s3
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have to be somewhat careful about dependencies not yet on CRAN, aws.s3 also should be in Suggests: as well as Remotes:.

License: MIT + file LICENSE
RoxygenNote: 5.0.1
4 changes: 4 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Generated by roxygen2: do not edit by hand

S3method(print,memoised)
export(cache_aws_s3)
export(cache_datastore)
export(cache_filesystem)
export(cache_local)
export(forget)
export(has_cache)
export(is.memoised)
Expand Down
72 changes: 72 additions & 0 deletions R/cache_aws_s3.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#' @name cache_aws_s3
#' @title Amazon Web Services S3 Cache
#' @description Initiate an Amazon Web Services Cache
#'
#' @examples
#'
#' \dontrun{
#' # Set AWS credentials.
#' Sys.setenv("AWS_ACCESS_KEY_ID" = "<access key>",
#' "AWS_SECRET_ACCESS_KEY" = "<access secret>")
#'
#' # Set up a unique bucket name.
#' s3 <- cache_aws_s3("unique-bucket-name")
#' mem_runif <- memoise(runif, cache = s3)
#' }
#'
#'
#' @param cache_name Bucket name for storing cache files.
#' @export

cache_aws_s3 <- function(cache_name) {

# Can't get this check to pass...
# if (!("aws.s3" %in% installed.packages()[,"Package"])) { stop("aws.s3 required for datastore cache.") }

if (!(aws.s3::bucket_exists(cache_name))) {
aws.s3::put_bucket(cache_name)
if (!(aws.s3::bucket_exists(cache_name))) {
stop("Cache name must use unique bucket name")
}
}

cache <- NULL
cache_reset <- function() {
aws.s3::delete_bucket(cache_name)
aws.s3::put_bucket(cache_name)
}

cache_set <- function(key, value) {
tfile = tempfile()
save(value, file = tfile)
aws.s3::put_object(tfile, object = key, bucket = cache_name)
}

cache_get <- function(key) {
suppressWarnings(aws.s3::s3load(object = key, bucket = cache_name))
base::get(ls()[ls() != "key"][[1]])
}

cache_has_key <- function(key) {
aws.s3::head_object(object = key, bucket = cache_name)
}

cache_keys <- function() {
items <- lapply(aws.s3::get_bucket(bucket = cache_name), function(x) {
if ("Key" %in% names(x)) {
return(x$Key)
} else {
return(NULL)
}
})
unlist(Filter(Negate(is.null), items))
}

list(
reset = cache_reset,
set = cache_set,
get = cache_get,
has_key = cache_has_key,
keys = cache_keys
)
}
136 changes: 136 additions & 0 deletions R/cache_datastore.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
#' @name cache_datastore
#' @title Google Datastore Cache
#' @description Initiate a Google Datastore cache.
#' @param project Google Cloud project
#' @param cache_name datastore kind to use for storing cache entities.
#'
#' @examples
#' \dontrun{
#' ds <- cache_datastore(project = "<project-id>", cache_name = "rcache")
#' mem_memoise(runif, cache = ds)
#' }
#'
#' @seealso \url{https://cloud.google.com/}
#' @seealso \url{https://cloud.google.com/datastore/docs/concepts/overview}
#'
#' @export

cache_datastore <- function(project, cache_name = "rcache") {

if (!("googleAuthR" %in% installed.packages()[,"Package"])) { stop("googleAuthR required for datastore cache.") }

options("googleAuthR.scopes.selected" = c("https://www.googleapis.com/auth/datastore",
"https://www.googleapis.com/auth/userinfo.email"))

googleAuthR::gar_auth()

base_url <- paste0("https://datastore.googleapis.com/v1beta3/projects/", project)

transaction <- googleAuthR::gar_api_generator(paste0(base_url, ":beginTransaction"),
"POST",
data_parse_function = function(x) x$transaction)

commit_ds <- googleAuthR::gar_api_generator(paste0(base_url, ":commit"),
"POST",
data_parse_function = function(x) x)

load_ds <- googleAuthR::gar_api_generator(paste0(base_url, ":lookup"),
"POST",
data_parse_function = function(resp) {
# Unserialize and return
if ("found" %in% names(resp)) {
resp <- resp$found
value <- resp$entity$properties$object$blobValue
response <- unserialize(memDecompress(base64enc::base64decode(value), type = "gzip"))
} else if ("missing" %in% names(resp)) {
"!cache-not-found"
} else {
stop("Error")
}
})

query_ds <- googleAuthR::gar_api_generator(paste0(base_url, ":runQuery"),
"POST",
data_parse_function = function(resp) resp)


cache_reset <- function() {
query_results <- query_ds(the_body = list(gqlQuery = list(queryString = paste0("SELECT * FROM ", cache_name))))
while((query_results$batch$moreResults != "NO_MORE_RESULTS") | is.null(query_results$batch$entityResults) == FALSE) {


ids <- (sapply(query_results$batch$entityResults$entity$key$path, function(x) x$name))

item_groups <- split(ids, (1:length(ids)) %/% 25)
sapply(item_groups, function(idset) {
mutations <- lapply(idset, function(x) {
c(list("delete" = list(path = list(kind = cache_name, name = x))))
})
body <- list(mutations = mutations, transaction = transaction())
resp <- try(commit_ds(the_body = body), silent = T)
message("Clearing Cache")
})
query_results <- query_ds(the_body = list(gqlQuery = list(queryString = paste0("SELECT * FROM ", cache_name))))
}
}


cache_set <- function(key, value) {
# Serialize value
svalue <- base64enc::base64encode(memCompress(serialize(value, NULL, ascii=T), type = "gzip"))
path_item <- list(
kind = cache_name,
name = key
)
prop = list(
object = list(blobValue = svalue, excludeFromIndexes = T)
)

transaction_id <- transaction()

key_obj <- c(list(key = list(path = path_item),
properties = prop))
mutation = list()
mutation[["upsert"]] = key_obj
body <- list(mutations = mutation,
transaction = transaction_id
)

resp <- try(commit_ds(the_body = body), silent = T)
if (class(resp) == "try-error") {
warning(attr(resp, "condition"))
}
}

cache_get <- function(key) {
path_item <- list(
kind = cache_name,
name = key
)

resp <- load_ds(the_body = list(keys = list(path = path_item)))
suppressWarnings( if(resp == "!cache-not-found") {
stop("Cache Not Found")
})
resp
}

cache_has_key <- function(key) {
res <- try(suppressWarnings(cache_get(key)), silent = TRUE)
if (class(res) != "try-error") {
message("Using Cached Version")
}
class(res) != "try-error"
}

list(
reset = cache_reset,
set = cache_set,
get = cache_get,
has_key = cache_has_key,
keys = function() message("Keys can't be listed with the google datastore cache.")
)
}



65 changes: 65 additions & 0 deletions R/cache_filesystem.r
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#' @name cache_filesystem
#' @title Filesystem Cache
#' @description
#' Initiate a filesystem cache.
#'
#' @param path Directory in which to store cached items.
#'
#' @examples
#'
#' \dontrun{
#' # Use with Dropbox
#'
#' db <- cache_filesystem("~/Dropbox/.rcache")
#'
#' mem_runif <- memoise(runif, cache = db)
#'
#' # Use with Google Drive
#'
#' gd <- cache_filesystem("~/Google Drive/.rcache")
#'
#' mem_runif <- memoise(runif, cache = gd)
#'
#' }
#'
#' @export

cache_filesystem <- function(path) {

dir.create(file.path(path), showWarnings = FALSE)

cache_reset <- function() {
cache_files <- list.files(path, full.names = TRUE)
# Use an environment for loaded items.
cache <- new.env(TRUE, emptyenv())
if (length(cache_files) > 0) {
rm_status <- file.remove(list.files(path, full.names = TRUE))
if (rm_status) {
message("Cached files removed.")
}
} else {
message("No files in Cache.")
}
}

cache_set <- function(key, value) {
save(value, file = paste(path, key, sep="/"))
}

cache_get <- function(key) {
load(file = paste(path, key, sep="/"))
value
}

cache_has_key <- function(key) {
file.exists(paste(path, key, sep="/"))
}

list(
reset = cache_reset,
set = cache_set,
get = cache_get,
has_key = cache_has_key,
keys = function() list.files(path)
)
}
10 changes: 9 additions & 1 deletion R/cache.r → R/cache_local.r
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
new_cache <- function() {
#' @name cache_local
#' @title In Memory Cache
#' @description Initiate an in memory cache.
#'
#' cache_local() stores cached items in memory. It is the default cache.
#'
#' @export

cache_local <- function() {

cache <- NULL
cache_reset <- function() {
Expand Down
5 changes: 2 additions & 3 deletions R/memoise.r
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#' @param ... optional variables specified as formulas with no RHS to use as
#' additional restrictions on caching. See Examples for usage.
#' @param envir Environment of the returned function.
#' @param cache Cache function.
#' @seealso \code{\link{forget}}, \code{\link{is.memoised}},
#' \code{\link{timeout}}, \url{http://en.wikipedia.org/wiki/Memoization}
#' @aliases memoise memoize
Expand Down Expand Up @@ -97,7 +98,7 @@
#' memA4 <- memoise(a, ~timeout(10))
#' memA4(2)
#' @importFrom stats setNames
memoise <- memoize <- function(f, ..., envir = environment(f)) {
memoise <- memoize <- function(f, ..., envir = environment(f), cache = cache_local()) {
f_formals <- formals(args(f))
if(is.memoised(f)) {
stop("`f` must not be memoised.", call. = FALSE)
Expand All @@ -113,8 +114,6 @@ memoise <- memoize <- function(f, ..., envir = environment(f)) {
init_call_args <- setNames(f_formal_name_list, f_formal_names)
init_call <- make_call(quote(`_f`), init_call_args)

cache <- new_cache()

validate_formulas(...)
additional <- list(...)

Expand Down
Loading