Skip to content

Commit

Permalink
Key Iterator & 1.0 compatibility (#19)
Browse files Browse the repository at this point in the history
- compatibility with 0.7+

- Key iterator

Iterate over a database with String keys with:

	for key in keys(cursor, String)
  • Loading branch information
madsciencetist authored and wildart committed Aug 30, 2018
1 parent 1955129 commit 637a483
Show file tree
Hide file tree
Showing 16 changed files with 126 additions and 78 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
deps/deps.jl
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ env:
- ARCH="i686"
- ARCH="x86_64"
julia:
- 0.6
- 0.7
- nightly
matrix:
exclude:
Expand All @@ -17,6 +17,6 @@ notifications:
email: false
script:
- if [[ -a .git/shallow ]]; then git fetch --unshallow; fi
- julia --check-bounds=yes -e 'Pkg.clone(pwd()); Pkg.build("LMDB"); Pkg.test("LMDB"; coverage=true)'
- julia --check-bounds=yes -e 'using Pkg; Pkg.build("LMDB"); Pkg.test("LMDB"; coverage=true)'
after_success:
- julia -e 'cd(Pkg.dir("LMDB")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())'
- julia -e 'Pkg.add("Coverage"); using Coverage; Codecov.submit(Codecov.process_folder())'
11 changes: 11 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
name = "LMDB"
uuid = "11f193de-5e89-5f17-923a-7d207d56daf9"
authors = ["Art Wild <[email protected]>"]
version = "0.1.0"

[deps]
BinDeps = "9e28174c-4ba2-5203-b857-d8d62c4213ee"
Docile = "e210f56a-9500-59e8-ae47-ce3a5fb1a75e"
Lexicon = "46b6dc52-43c1-5dc0-9d43-b3fa04378dc4"
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
2 changes: 0 additions & 2 deletions REQUIRE

This file was deleted.

4 changes: 2 additions & 2 deletions deps/build.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BinDeps
using BinDeps, Libdl

@BinDeps.setup

Expand All @@ -22,4 +22,4 @@ provides(BuildProcess,
end)
end), liblmdb)

@BinDeps.install Dict( :liblmdb => :liblmdb)
@BinDeps.install Dict( :liblmdb => :liblmdb)
6 changes: 3 additions & 3 deletions src/LMDB.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
__precompile__(true)
module LMDB

isdefined(:Docile) && eval(:(@document))
eval(:(@isdefined(Docile) && eval(:(@document))))

import Base: open, close, getindex, setindex!, put!, start, reset,
isopen, count, delete!, info, get, show, convert, show
isopen, count, delete!, info, keys, get, show, convert, show
import Base.Iterators: drop

depsfile = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
Expand All @@ -16,7 +16,7 @@ module LMDB

export Environment, create, open, close, sync, set!, unset!, getindex, setindex!, path, info, show,
Transaction, start, abort, commit, reset, renew, environment,
DBI, drop, delete!, get, put!,
DBI, drop, delete!, keys, get, put!,
Cursor, count, transaction, database,
isflagset, isopen,
LMDBError, CursorOps
Expand Down
12 changes: 6 additions & 6 deletions src/common.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,27 @@ const Cmode_t = Cushort
"Generic structure used for passing keys and data in and out of the database."
struct MDBValue
size::Csize_t # size of the data item
data::Ptr{Void} # address of the data item
data::Ptr{Nothing} # address of the data item
end

MDBValue() = MDBValue(zero(Csize_t), C_NULL)
MDBValue(_::Void) = MDBValue()
MDBValue(_::Nothing) = MDBValue()
MDBValue(val::String) = MDBValue(sizeof(val), pointer(val))
function MDBValue(val::T) where {T}
isbits(T) && error("Can not wrap a $T in MDBValue. Use a $T array instead")
isbitstype(T) && error("Can not wrap a $T in MDBValue. Use a $T array instead")
val_size = sizeof(eltype(val))*length(val)
return MDBValue(val_size, pointer(val))
end

convert{T}(::Type{T}, mdb_val_ref::Ref{MDBValue}) = _convert(T, mdb_val_ref[])
convert(::Type{T}, mdb_val_ref::Ref{MDBValue}) where {T} = _convert(T, mdb_val_ref[])
function _convert(::Type{String}, mdb_val::MDBValue)
unsafe_string(convert(Ptr{UInt8}, mdb_val.data), mdb_val.size)
end
function _convert{T}(::Type{Vector{T}}, mdb_val::MDBValue)
function _convert(::Type{Vector{T}}, mdb_val::MDBValue) where {T}
res = unsafe_wrap(Array, convert(Ptr{UInt8}, mdb_val.data), mdb_val.size)
reinterpret(T,res)
end
function _convert{T}(::Type{T}, mdb_val::MDBValue)
function _convert(::Type{T}, mdb_val::MDBValue) where {T}
unsafe_load(convert(Ptr{T}, mdb_val.data))
end

Expand Down
66 changes: 51 additions & 15 deletions src/cur.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@
A handle to a cursor structure for navigating through a database.
"""
mutable struct Cursor
handle::Ptr{Void}
Cursor(cur::Ptr{Void}) = new(cur)
handle::Ptr{Nothing}
Cursor(cur::Ptr{Nothing}) = new(cur)
end

"Check if cursor is open"
isopen(cur::Cursor) = cur.handle != C_NULL

"Create a cursor"
function open(txn::Transaction, dbi::DBI)
cur_ptr_ref = Ref{Ptr{Void}}(C_NULL)
cur_ptr_ref = Ref{Ptr{Nothing}}(C_NULL)
ret = ccall((:mdb_cursor_open, liblmdb), Cint,
(Ptr{Void}, Cuint, Ptr{Ptr{Void}}),
(Ptr{Nothing}, Cuint, Ptr{Ptr{Nothing}}),
txn.handle, dbi.handle, cur_ptr_ref)
(ret != 0) && throw(LMDBError(ret))
return Cursor(cur_ptr_ref[])
Expand All @@ -34,46 +34,82 @@ function close(cur::Cursor)
if cur.handle == C_NULL
warn("Cursor is already closed")
end
ccall((:mdb_cursor_close, liblmdb), Void, (Ptr{Void},), cur.handle)
ccall((:mdb_cursor_close, liblmdb), Nothing, (Ptr{Nothing},), cur.handle)
cur.handle = C_NULL
return
end

"Renew a cursor"
function renew(txn::Transaction, cur::Cursor)
ret = ccall((:mdb_cursor_renew, liblmdb), Cint,
(Ptr{Void}, Ptr{Void}), txn.handle, cur.handle)
(Ptr{Nothing}, Ptr{Nothing}), txn.handle, cur.handle)
(ret != 0) && throw(LMDBError(ret))
return ret
end

"Return the cursor's transaction"
function transaction(cur::Cursor)
txn_ptr = ccall((:mdb_cursor_txn, liblmdb), Ptr{Void}, (Ptr{Void},), cur.handle)
txn_ptr = ccall((:mdb_cursor_txn, liblmdb), Ptr{Nothing}, (Ptr{Nothing},), cur.handle)
(txn_ptr == C_NULL) && return nothing
return Transaction(txn_ptr)
end

"Return the cursor's database"
function database(cur::Cursor)
dbi = ccall((:mdb_cursor_dbi, liblmdb), Cuint, (Ptr{Void},), cur.handle)
dbi = ccall((:mdb_cursor_dbi, liblmdb), Cuint, (Ptr{Nothing},), cur.handle)
(dbi == 0) && return nothing
return DBI(dbi, "")
end

"Type to implement the Iterator interface"
mutable struct KeyIterator
cur::Cursor
keytype::Type
end

"Iterate over keys"
function Base.iterate(iter::KeyIterator, first=true)
# Setup parameters
mdb_key_ref = Ref(MDBValue())
mdb_val_ref = Ref(MDBValue())
NOTFOUND::Cint = -30798

cursor_op = first ? FIRST : NEXT
ret = ccall( (:mdb_cursor_get, liblmdb), Cint,
(Ptr{Nothing}, Ptr{MDBValue}, Ptr{MDBValue}, Cint),
iter.cur.handle, mdb_key_ref, mdb_val_ref, Cint(cursor_op))

if ret == 0
# Convert to proper type
return (convert(iter.keytype, mdb_key_ref), false)
elseif ret == NOTFOUND
return nothing
else
throw(LMDBError(ret))
end
end

Base.IteratorSize(::KeyIterator) = Base.SizeUnknown()
Base.eltype(iter::KeyIterator) = iter.keytype

"Return iterator over keys of uniform, specified type"
function keys(cur::Cursor, keytype::Type{T}) where T
return KeyIterator(cur, keytype)
end

"""Retrieve by cursor.
This function retrieves key/data pairs from the database.
"""
function get(cur::Cursor, key, ::Type{T}, op::CursorOps=SET_KEY) where T
# Setup parameters
k = isbits(typeof(key)) ? [key] : key
k = isbitstype(typeof(key)) ? [key] : key
mdb_key_ref = Ref(MDBValue(k))
mdb_val_ref = Ref(MDBValue())

# Get value
ret = ccall( (:mdb_cursor_get, liblmdb), Cint,
(Ptr{Void}, Ptr{MDBValue}, Ptr{MDBValue}, Cint),
(Ptr{Nothing}, Ptr{MDBValue}, Ptr{MDBValue}, Cint),
cur.handle, mdb_key_ref, mdb_val_ref, Cint(op))
(ret != 0) && throw(LMDBError(ret))

Expand All @@ -86,13 +122,13 @@ end
This function stores key/data pairs into the database. The cursor is positioned at the new item, or on failure usually near it.
"""
function put!(cur::Cursor, key, val; flags::Cuint = zero(Cuint))
k = isbits(typeof(key)) ? [key] : key
k = isbitstype(typeof(key)) ? [key] : key
mdb_key_ref = Ref(MDBValue(k))
v = isbits(typeof(val)) ? [val] : val
v = isbitstype(typeof(val)) ? [val] : val
mdb_val_ref = Ref(MDBValue(v))

ret = ccall((:mdb_cursor_put, liblmdb), Cint,
(Ptr{Void}, Ptr{MDBValue}, Ptr{MDBValue}, Cuint),
(Ptr{Nothing}, Ptr{MDBValue}, Ptr{MDBValue}, Cuint),
cur.handle, mdb_key_ref, mdb_val_ref, flags)

(ret != 0) && throw(LMDBError(ret))
Expand All @@ -102,7 +138,7 @@ end
"Delete current key/data pair to which the cursor refers"
function delete!(cur::Cursor; flags::Cuint = zero(Cuint))
ret = ccall((:mdb_cursor_del, liblmdb), Cint,
(Ptr{Void}, Cuint), cur.handle, flags)
(Ptr{Nothing}, Cuint), cur.handle, flags)
(ret != 0) && throw(LMDBError(ret))
return ret
end
Expand All @@ -111,7 +147,7 @@ end
function count(cur::Cursor)
countp = Csize_t[0]
ret = ccall( (:mdb_cursor_count, liblmdb), Cint,
(Ptr{Void}, Csize_t), cur.handle, countp)
(Ptr{Nothing}, Csize_t), cur.handle, countp)
(ret != 0) && throw(LMDBError(ret))
return Int(countp[1])
end
24 changes: 12 additions & 12 deletions src/dbi.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ function open(txn::Transaction, dbname::String = ""; flags::Cuint = zero(Cuint))
cdbname = length(dbname) > 0 ? dbname : convert(Cstring, Ptr{UInt8}(C_NULL))
handle = Cuint[0]
ret = ccall((:mdb_dbi_open, liblmdb), Cint,
(Ptr{Void}, Cstring, Cuint, Ptr{Cuint}),
(Ptr{Nothing}, Cstring, Cuint, Ptr{Cuint}),
txn.handle, cdbname, flags, handle)
(ret != 0) && throw(LMDBError(ret))
return DBI(handle[1], dbname)
Expand All @@ -37,7 +37,7 @@ function close(env::Environment, dbi::DBI)
if !isopen(env)
warn("Environment is closed")
end
ccall((:mdb_dbi_close, liblmdb), Void, (Ptr{Void}, Cuint), env.handle, dbi.handle)
ccall((:mdb_dbi_close, liblmdb), Nothing, (Ptr{Nothing}, Cuint), env.handle, dbi.handle)
dbi.handle = zero(Cuint)
return
end
Expand All @@ -46,7 +46,7 @@ end
function flags(txn::Transaction, dbi::DBI)
flags = Cuint[0]
ret = ccall((:mdb_dbi_flags, liblmdb), Cint,
(Ptr{Void}, Cuint, Ptr{Cuint}),
(Ptr{Nothing}, Cuint, Ptr{Cuint}),
txn.handle, dbi.handle, flags)
(ret != 0) && throw(LMDBError(ret))
return flags[1]
Expand All @@ -60,21 +60,21 @@ DB will be deleted from the environment and DB handle will be closed
function drop(txn::Transaction, dbi::DBI; delete = false)
del = delete ? Int32(1) : Int32(0)
ret = ccall((:mdb_drop, liblmdb), Cint,
(Ptr{Void}, Cuint, Cint),
(Ptr{Nothing}, Cuint, Cint),
txn.handle, dbi.handle, del)
(ret != 0) && throw(LMDBError(ret))
return ret
end

"Store items into a database"
function put!(txn::Transaction, dbi::DBI, key, val; flags::Cuint = zero(Cuint))
k = isbits(typeof(key)) ? [key] : key
k = isbitstype(typeof(key)) ? [key] : key
mdb_key_ref = Ref(MDBValue(k))
v = isbits(typeof(val)) ? [val] : val
v = isbitstype(typeof(val)) ? [val] : val
mdb_val_ref = Ref(MDBValue(v))

ret = ccall((:mdb_put, liblmdb), Cint,
(Ptr{Void}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}, Cuint),
(Ptr{Nothing}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}, Cuint),
txn.handle, dbi.handle, mdb_key_ref, mdb_val_ref, flags)

(ret != 0) && throw(LMDBError(ret))
Expand All @@ -83,13 +83,13 @@ end

"Delete items from a database"
function delete!(txn::Transaction, dbi::DBI, key, val=C_NULL)
k = isbits(typeof(key)) ? [key] : key
k = isbitstype(typeof(key)) ? [key] : key
mdb_key_ref = Ref(MDBValue(k))
v = isbits(typeof(val)) ? [val] : val
v = isbitstype(typeof(val)) ? [val] : val
mdb_val_ref = Ref((val === C_NULL) ? MDBValue() : MDBValue(v))

ret = ccall((:mdb_del, liblmdb), Cint,
(Ptr{Void}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}),
(Ptr{Nothing}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}),
txn.handle, dbi.handle, mdb_key_ref, mdb_val_ref)

(ret != 0) && throw(LMDBError(ret))
Expand All @@ -99,13 +99,13 @@ end
"Get items from a database"
function get(txn::Transaction, dbi::DBI, key, ::Type{T}) where T
# Setup parameters
k = isbits(typeof(key)) ? [key] : key
k = isbitstype(typeof(key)) ? [key] : key
mdb_key_ref = Ref(MDBValue(k))
mdb_val_ref = Ref(MDBValue())

# Get value
ret = ccall((:mdb_get, liblmdb), Cint,
(Ptr{Void}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}),
(Ptr{Nothing}, Cuint, Ptr{MDBValue}, Ptr{MDBValue}),
txn.handle, dbi.handle, mdb_key_ref, mdb_val_ref)
(ret != 0) && throw(LMDBError(ret))

Expand Down
Loading

0 comments on commit 637a483

Please sign in to comment.