Update LMDB blittable safety checks
This commit is contained in:
Vendored
+4
-4
@@ -68,9 +68,9 @@ main :: proc() {
|
|||||||
db_handle: mdb.Dbi
|
db_handle: mdb.Dbi
|
||||||
// Put transaction
|
// Put transaction
|
||||||
key := 7
|
key := 7
|
||||||
key_val := mdb.blittable_val(&key)
|
key_val := mdb.pod_val(&key)
|
||||||
put_data := 12
|
put_data := 12
|
||||||
put_data_val := mdb.blittable_val(&put_data)
|
put_data_val := mdb.pod_val(&put_data)
|
||||||
mdb.panic_on_err(mdb.txn_begin(environment, nil, {}, &txn_handle))
|
mdb.panic_on_err(mdb.txn_begin(environment, nil, {}, &txn_handle))
|
||||||
mdb.panic_on_err(mdb.dbi_open(txn_handle, nil, {}, &db_handle))
|
mdb.panic_on_err(mdb.dbi_open(txn_handle, nil, {}, &db_handle))
|
||||||
mdb.panic_on_err(mdb.put(txn_handle, db_handle, &key_val, &put_data_val, {}))
|
mdb.panic_on_err(mdb.put(txn_handle, db_handle, &key_val, &put_data_val, {}))
|
||||||
@@ -80,7 +80,7 @@ main :: proc() {
|
|||||||
data_val: mdb.Val
|
data_val: mdb.Val
|
||||||
mdb.panic_on_err(mdb.txn_begin(environment, nil, {}, &txn_handle))
|
mdb.panic_on_err(mdb.txn_begin(environment, nil, {}, &txn_handle))
|
||||||
mdb.panic_on_err(mdb.get(txn_handle, db_handle, &key_val, &data_val))
|
mdb.panic_on_err(mdb.get(txn_handle, db_handle, &key_val, &data_val))
|
||||||
data_cpy := mdb.blittable_copy(data_val, int)
|
data_cpy := mdb.pod_copy(data_val, int)
|
||||||
mdb.panic_on_err(mdb.txn_commit(txn_handle))
|
mdb.txn_abort(txn_handle)
|
||||||
fmt.println("Get result:", data_cpy)
|
fmt.println("Get result:", data_cpy)
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+51
-14
@@ -169,58 +169,86 @@ import "core:fmt"
|
|||||||
import "core:reflect"
|
import "core:reflect"
|
||||||
import "core:sys/posix"
|
import "core:sys/posix"
|
||||||
|
|
||||||
|
import b "../../basic"
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
// ----- Added Odin Helpers ------------------------
|
// ----- Added Odin Helpers ------------------------
|
||||||
// ---------------------------------------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
// Wrap a blittable value's bytes as an LMDB Val.
|
// Wrap a POD value's bytes as an LMDB Val.
|
||||||
// T must be a contiguous type with no indirection (no pointers, slices, strings, maps, etc.).
|
// T must be a contiguous type with no indirection (no pointers, slices, strings, maps, etc.).
|
||||||
blittable_val :: #force_inline proc(val_ptr: ^$T) -> Val {
|
pod_val :: #force_inline proc(val_ptr: ^$T) -> Val {
|
||||||
|
when ODIN_DEBUG {
|
||||||
fmt.assertf(
|
fmt.assertf(
|
||||||
reflect.has_no_indirections(type_info_of(T)),
|
reflect.has_no_indirections(type_info_of(T)),
|
||||||
"blitval: type '%v' contains indirection and cannot be stored directly in LMDB",
|
"pod_val: type '%v' contains indirection and cannot be stored directly in LMDB",
|
||||||
typeid_of(T),
|
typeid_of(T),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
return Val{size_of(T), val_ptr}
|
return Val{size_of(T), val_ptr}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads a blittable T out of the LMDB memory map by copying it into caller
|
// Reads a POD T out of the LMDB memory map by copying it into caller
|
||||||
// storage. The returned T has no lifetime tie to the transaction.
|
// storage. The returned T has no lifetime tie to the transaction.
|
||||||
blittable_copy :: #force_inline proc(val: Val, $T: typeid) -> T {
|
pod_copy :: #force_inline proc(val: Val, $T: typeid) -> T {
|
||||||
|
when ODIN_DEBUG {
|
||||||
fmt.assertf(
|
fmt.assertf(
|
||||||
reflect.has_no_indirections(type_info_of(T)),
|
reflect.has_no_indirections(type_info_of(T)),
|
||||||
"blitval_copy: type '%v' contains indirection and cannot be read directly from LMDB",
|
"pod_copy: type '%v' contains indirection and cannot be read directly from LMDB",
|
||||||
typeid_of(T),
|
typeid_of(T),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
when b.ODIN_BOUNDS_CHECK {
|
||||||
|
fmt.assertf(
|
||||||
|
val.size == size_of(T),
|
||||||
|
"size_of(%v) (%v) != val.size (%v)",
|
||||||
|
typeid_of(T),
|
||||||
|
size_of(T),
|
||||||
|
val.size,
|
||||||
|
)
|
||||||
|
}
|
||||||
return (cast(^T)val.data)^
|
return (cast(^T)val.data)^
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero-copy pointer view into the LMDB memory map as a ^T.
|
// Zero-copy pointer view into the LMDB memory map as a ^T.
|
||||||
// Useful for large blittable types where you want to read individual fields
|
// Useful for large POD types where you want to read individual fields
|
||||||
// without copying the entire value (e.g. ptr.timestamp, ptr.flags).
|
// without copying the entire value (e.g. ptr.timestamp, ptr.flags).
|
||||||
// MUST NOT be written through — writes either segfault (default env mode)
|
// MUST NOT be written through — writes either segfault (default env mode)
|
||||||
// or silently corrupt the database (ENV_WRITEMAP).
|
// or silently corrupt the database (ENV_WRITEMAP).
|
||||||
// MUST NOT be retained past txn_commit, txn_abort, or any subsequent write
|
// MUST NOT be retained past txn_commit, txn_abort, or any subsequent write
|
||||||
// operation on the same env — the pointer is invalidated.
|
// operation on the same env — the pointer is invalidated.
|
||||||
blittable_view :: #force_inline proc(val: Val, $T: typeid) -> ^T {
|
pod_view :: #force_inline proc(val: Val, $T: typeid) -> ^T {
|
||||||
|
when ODIN_DEBUG {
|
||||||
fmt.assertf(
|
fmt.assertf(
|
||||||
reflect.has_no_indirections(type_info_of(T)),
|
reflect.has_no_indirections(type_info_of(T)),
|
||||||
"blitval_view: type '%v' contains indirection and cannot be viewed directly from LMDB",
|
"pod_view: type '%v' contains indirection and cannot be viewed directly from LMDB",
|
||||||
typeid_of(T),
|
typeid_of(T),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
when b.ODIN_BOUNDS_CHECK {
|
||||||
|
fmt.assertf(
|
||||||
|
val.size == size_of(T),
|
||||||
|
"size_of(%v) (%v) != val.size (%v)",
|
||||||
|
typeid_of(T),
|
||||||
|
size_of(T),
|
||||||
|
val.size,
|
||||||
|
)
|
||||||
|
}
|
||||||
return cast(^T)val.data
|
return cast(^T)val.data
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wrap a slice of blittable elements as an LMDB Val for use with put/get.
|
// Wrap a slice of POD elements as an LMDB Val for use with put/get.
|
||||||
// T must be a contiguous type with no indirection.
|
// T must be a contiguous type with no indirection.
|
||||||
// The caller's slice must remain valid (not freed, not resized) for the
|
// The caller's slice must remain valid (not freed, not resized) for the
|
||||||
// duration of the put call that consumes this Val.
|
// duration of the put call that consumes this Val.
|
||||||
slice_val :: #force_inline proc(s: []$T) -> Val {
|
pod_slice_val :: #force_inline proc(s: []$T) -> Val {
|
||||||
|
when ODIN_DEBUG {
|
||||||
fmt.assertf(
|
fmt.assertf(
|
||||||
reflect.has_no_indirections(type_info_of(T)),
|
reflect.has_no_indirections(type_info_of(T)),
|
||||||
"slice_val: element type '%v' contains indirection and cannot be stored directly in LMDB",
|
"pod_slice_val: element type '%v' contains indirection and cannot be stored directly in LMDB",
|
||||||
typeid_of(T),
|
typeid_of(T),
|
||||||
)
|
)
|
||||||
|
}
|
||||||
return Val{uint(len(s) * size_of(T)), raw_data(s)}
|
return Val{uint(len(s) * size_of(T)), raw_data(s)}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,12 +259,21 @@ slice_val :: #force_inline proc(s: []$T) -> Val {
|
|||||||
// MUST be copied (e.g. slice.clone) if it needs to outlive the current
|
// MUST be copied (e.g. slice.clone) if it needs to outlive the current
|
||||||
// transaction; the view is invalidated by txn_commit, txn_abort, or any
|
// transaction; the view is invalidated by txn_commit, txn_abort, or any
|
||||||
// subsequent write operation on the same env.
|
// subsequent write operation on the same env.
|
||||||
slice_view :: #force_inline proc(val: Val, $T: typeid) -> []T {
|
pod_slice_view :: #force_inline proc(val: Val, $T: typeid) -> []T {
|
||||||
|
when ODIN_DEBUG {
|
||||||
fmt.assertf(
|
fmt.assertf(
|
||||||
reflect.has_no_indirections(type_info_of(T)),
|
reflect.has_no_indirections(type_info_of(T)),
|
||||||
"slice_view: element type '%v' contains indirection and cannot be read directly from LMDB",
|
"pod_slice_view: element type '%v' contains indirection and cannot be read directly from LMDB",
|
||||||
typeid_of(T),
|
typeid_of(T),
|
||||||
)
|
)
|
||||||
|
fmt.assertf(
|
||||||
|
val.size % size_of(T) == 0,
|
||||||
|
"pod_slice_view: val.size (%v) is not a multiple of size_of(%v) (%v)",
|
||||||
|
val.size,
|
||||||
|
typeid_of(T),
|
||||||
|
size_of(T),
|
||||||
|
)
|
||||||
|
}
|
||||||
return (cast([^]T)val.data)[:val.size / size_of(T)]
|
return (cast([^]T)val.data)[:val.size / size_of(T)]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user