Proxy object. These exist to try and exploit LMDB's copy-free design. LMDB can pass back a read-only pointer to memory without copying it. So rather than immediately trying to read the whole thing in, this class provides a "proxy" to the data. At the moment they're not terribly useful - all you can do is get the length, and peek at the first bytes! They are used internally in the package to support cursors.

Methods

data

Return the value from a proxy object

Usage: data(as_raw = NULL)

Arguments:

  • as_raw: Return the value as a raw vector? This has the same semantics as mdb_env$get - if NULL then the value will be returned as a string as possible, otherwise as a raw vector. If TRUE then the value is always returned as a raw vector, and if FALSE then the value is always returned as a string (or an error is thrown if that is not possible).

Value: A string or raw vector

head

Read the first n bytes from a proxy

Usage: head(n = 6L, as_raw = NULL)

Arguments:

  • n: The number of bytes to read. If n is greater than the length of the object the whole object is returned (same behaviour as head

  • as_raw: As for $data()

is_raw

Return whether we know a value to be raw or not. This is affected by whether we have successfully turned the value into a string (in which case we can return FALSE) or if any NULL bytes have been detected. The latter condition may be satisfied by reading the first bit of the proxy with $head()

Usage: is_raw()

Value: A logical if we can, otherwise NULL (for symmetry with as_raw)

is_valid

Test if a proxy object is still valid. Once the proxy is invalid, it cannot be read from any more. Proxies are invalidated if their parent transaction is closed, or if any write operations (e.g., put, del) have occurred.

Usage: is_valid()

Value: Scalar logical

size

The size of the data - the number of characters in the string, or number of bytes in the raw vector.

Usage: size()

Value: Scalar integer

Examples

# Start with a write transaction that has written a little data:
env <- thor::mdb_env(tempfile())
txn <- env$begin(write = TRUE)
txn$put("a", "apple")
txn$put("b", "banana")

# We can get a proxy object back by passing as_proxy = TRUE
p <- txn$get("a", as_proxy = TRUE)
p
#> <mdb_val_proxy>
#>   Public:
#>     data(as_raw = NULL)
#>     head(n = 6L, as_raw = NULL)
#>     is_raw()
#>     is_valid()
#>     size()

# Without copying anything we can get the length of the data
p$size() # == nchar("apple")
#> [1] 5

# And of course we can get the data
p$data()
#> [1] "apple"
p$data(as_raw = TRUE)
#> [1] 61 70 70 6c 65

# Referencing an invalid proxy is an error, but you can use
# "is_valid()" check to see if it is valid
p$is_valid()
#> [1] TRUE

txn$put("c", "cabbage")
p$is_valid()
#> [1] FALSE
try(p$data())
#> Error in assert_valid() : 
#>   mdb_val_proxy is invalid: transaction has modified database

# It is possible to read the first few bytes; this might be useful
# to determine if (say) a value is a serialised R object:
txn$put("d", serialize(mtcars, NULL))

# The first 6 bytes of a binary serialised rds object is always
#
#   0x58 0x0a 0x00 0x00 0x00 0x02
#
# for XDR serialisation, or
#
#   0x42 0x0a 0x02 0x00 0x00 0x00
#
# for native little-endian serialisation.
#
# So with a little helper function
is_rds <- function(x) {
  h_xdr <- as.raw(c(0x58, 0x0a, 0x00, 0x00, 0x00, 0x02))
  h_bin <- as.raw(c(0x42, 0x0a, 0x02, 0x00, 0x00, 0x00))
  x6 <- head(x, 6L)
  identical(x6, h_xdr) || identical(x6, h_bin)
}

# We can see that the value stored at 'a' is not rds
p1 <- txn$get("a", as_proxy = TRUE)
is_rds(p1$head(6, as_raw = TRUE))
#> [1] FALSE

# But the value stored at 'd' is:
p2 <- txn$get("d", as_proxy = TRUE)
is_rds(p2$head(6, as_raw = TRUE))
#> [1] FALSE

# Retrieve and unserialise the value:
head(unserialize(p2$data()))
#>                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
#> Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
#> Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
#> Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
#> Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
#> Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
#> Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1