Skip to content

Commit 777f6a7

Browse files
authored
Create New Pybind11 Context Constructor That Takes in Capsule (#1165)
* Create a custom constructor for `Context` that takes in a Python object. Use `keep_alive<1, 2>` to increase the refcount of the `tiledb.Ctx` object so that it not garbage collected prior to the `Group` object. * Previously, the `Group` constructor was using a constructor for `Context` that took in a capsule object. Because the Pybind11 `Group` has no knowledge of the Cython `Ctx`, the `tiledb_ctx_t *` pointer would be freed prior to `~Group` despite the usage of `keep_alive<1, 2>`. This would cause a segfault.
1 parent c337c24 commit 777f6a7

File tree

4 files changed

+24
-3
lines changed

4 files changed

+24
-3
lines changed

HISTORY.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
* Use `bool` instead of `uint8` for Boolean dtype in `dataframe_.py` [#1154](https://github.com/TileDB-Inc/TileDB-Py/pull/1154)
55
* Support QueryCondition OR operator [#1146](https://github.com/TileDB-Inc/TileDB-Py/pull/1146)
66

7+
## Bug Fixes
8+
* Fix error where passing a `Context` to `Group` would segfault intermittenly [#1165](https://github.com/TileDB-Inc/TileDB-Py/pull/1165)
9+
710
# TileDB-Py 0.15.3 Release Notes
811

912
## TileDB Embedded updates:

tiledb/cc/context.cc

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ void init_context(py::module &m) {
1515
.def(py::init())
1616
.def(py::init<Config>())
1717
.def(py::init<py::capsule, bool>())
18+
.def(py::init([](py::object ctx, bool own) {
19+
return Context(py::capsule(ctx.attr("__capsule__")()), own);
20+
}),
21+
py::keep_alive<1, 2>())
1822

19-
.def_property_readonly("config", &Context::config)
23+
.def("config", &Context::config)
2024
.def("set_tag", &Context::set_tag)
2125
.def("get_stats", &Context::stats)
2226
.def("is_supported_fs", &Context::is_supported_fs);

tiledb/group.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def clear(self):
245245

246246
def __init__(self, uri: str, mode: str = "r", ctx: "Ctx" = None):
247247
self._ctx = ctx or default_ctx()
248-
cctx = lt.Context(self._ctx.__capsule__(), False)
248+
cctx = lt.Context(self._ctx, False)
249249

250250
if mode not in Group._mode_to_query_type:
251251
raise ValueError(f"invalid mode {mode}")
@@ -266,7 +266,7 @@ def create(uri: str, ctx: "Ctx" = None):
266266
:type ctx: tiledb.Ctx
267267
"""
268268
_ctx = ctx or default_ctx()
269-
cctx = lt.Context(_ctx.__capsule__(), False)
269+
cctx = lt.Context(_ctx, False)
270270
lt.Group._create(cctx, uri)
271271

272272
def open(self, mode: str = "r"):

tiledb/tests/test_group.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,3 +479,17 @@ def test_basic(self, test_vals):
479479
grp = tiledb.Group(path, "r")
480480
self.assert_metadata_roundtrip(grp.meta, test_vals)
481481
grp.close()
482+
483+
def test_pass_context(self):
484+
foo = self.path("foo")
485+
bar = self.path("foo/bar")
486+
487+
tiledb.group_create(foo)
488+
tiledb.group_create(bar)
489+
490+
ctx = tiledb.Ctx()
491+
with tiledb.Group(foo, mode="w", ctx=ctx) as G:
492+
G.add(bar, name="bar")
493+
494+
with tiledb.Group(foo, mode="r", ctx=ctx) as G:
495+
assert "bar" in G

0 commit comments

Comments
 (0)