Skip to content

Commit 73c5815

Browse files
committed
extmod/modbtree: Retain reference to underlying stream so it's not GC'd.
For ports that have a system malloc which is not garbage collected (eg unix, esp32), the stream object for the DB must be retained separately to prevent it from being reclaimed by the MicroPython GC (because the berkeley-db library uses malloc to allocate the DB structure which stores the only reference to the stream). Although in some cases the user code will explicitly retain a reference to the underlying stream because it needs to call close() on it, this is not always the case, eg in cases where the DB is intended to live forever. Fixes issue adafruit#5940.
1 parent 391927c commit 73c5815

4 files changed

Lines changed: 108 additions & 3 deletions

File tree

examples/natmod/btree/btree_c.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ STATIC mp_obj_t btree_open(size_t n_args, const mp_obj_t *args) {
115115
mp_raise_OSError(native_errno);
116116
}
117117

118-
return MP_OBJ_FROM_PTR(btree_new(db));
118+
return MP_OBJ_FROM_PTR(btree_new(db, args[0]));
119119
}
120120
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(btree_open_obj, 5, 5, btree_open);
121121

extmod/modbtree.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939

4040
typedef struct _mp_obj_btree_t {
4141
mp_obj_base_t base;
42+
mp_obj_t stream; // retain a reference to prevent GC from reclaiming it
4243
DB *db;
4344
mp_obj_t start_key;
4445
mp_obj_t end_key;
@@ -65,9 +66,10 @@ void __dbpanic(DB *db) {
6566
mp_printf(&mp_plat_print, "__dbpanic(%p)\n", db);
6667
}
6768

68-
STATIC mp_obj_btree_t *btree_new(DB *db) {
69+
STATIC mp_obj_btree_t *btree_new(DB *db, mp_obj_t stream) {
6970
mp_obj_btree_t *o = m_new_obj(mp_obj_btree_t);
7071
o->base.type = &btree_type;
72+
o->stream = stream;
7173
o->db = db;
7274
o->start_key = mp_const_none;
7375
o->end_key = mp_const_none;
@@ -361,7 +363,7 @@ STATIC mp_obj_t mod_btree_open(size_t n_args, const mp_obj_t *pos_args, mp_map_t
361363
if (db == NULL) {
362364
mp_raise_OSError(errno);
363365
}
364-
return MP_OBJ_FROM_PTR(btree_new(db));
366+
return MP_OBJ_FROM_PTR(btree_new(db, pos_args[0]));
365367
}
366368
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(mod_btree_open_obj, 1, mod_btree_open);
367369

tests/extmod/btree_gc.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Test btree interaction with the garbage collector.
2+
3+
try:
4+
import btree, uio, gc
5+
except ImportError:
6+
print("SKIP")
7+
raise SystemExit
8+
9+
N = 80
10+
11+
# Create a BytesIO but don't keep a reference to it.
12+
db = btree.open(uio.BytesIO(), pagesize=512)
13+
14+
# Overwrite lots of the Python stack to make sure no reference to the BytesIO remains.
15+
x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
16+
17+
# Write lots of key/value pairs, which fill up the DB and also allocate temporary heap
18+
# memory due to the string addition, and do a GC collect to verify that the BytesIO
19+
# is not collected.
20+
for i in range(N):
21+
db[b"thekey" + str(i)] = b"thelongvalue" + str(i)
22+
print(db[b"thekey" + str(i)])
23+
gc.collect()

tests/extmod/btree_gc.py.exp

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
b'thelongvalue0'
2+
b'thelongvalue1'
3+
b'thelongvalue2'
4+
b'thelongvalue3'
5+
b'thelongvalue4'
6+
b'thelongvalue5'
7+
b'thelongvalue6'
8+
b'thelongvalue7'
9+
b'thelongvalue8'
10+
b'thelongvalue9'
11+
b'thelongvalue10'
12+
b'thelongvalue11'
13+
b'thelongvalue12'
14+
b'thelongvalue13'
15+
b'thelongvalue14'
16+
b'thelongvalue15'
17+
b'thelongvalue16'
18+
b'thelongvalue17'
19+
b'thelongvalue18'
20+
b'thelongvalue19'
21+
b'thelongvalue20'
22+
b'thelongvalue21'
23+
b'thelongvalue22'
24+
b'thelongvalue23'
25+
b'thelongvalue24'
26+
b'thelongvalue25'
27+
b'thelongvalue26'
28+
b'thelongvalue27'
29+
b'thelongvalue28'
30+
b'thelongvalue29'
31+
b'thelongvalue30'
32+
b'thelongvalue31'
33+
b'thelongvalue32'
34+
b'thelongvalue33'
35+
b'thelongvalue34'
36+
b'thelongvalue35'
37+
b'thelongvalue36'
38+
b'thelongvalue37'
39+
b'thelongvalue38'
40+
b'thelongvalue39'
41+
b'thelongvalue40'
42+
b'thelongvalue41'
43+
b'thelongvalue42'
44+
b'thelongvalue43'
45+
b'thelongvalue44'
46+
b'thelongvalue45'
47+
b'thelongvalue46'
48+
b'thelongvalue47'
49+
b'thelongvalue48'
50+
b'thelongvalue49'
51+
b'thelongvalue50'
52+
b'thelongvalue51'
53+
b'thelongvalue52'
54+
b'thelongvalue53'
55+
b'thelongvalue54'
56+
b'thelongvalue55'
57+
b'thelongvalue56'
58+
b'thelongvalue57'
59+
b'thelongvalue58'
60+
b'thelongvalue59'
61+
b'thelongvalue60'
62+
b'thelongvalue61'
63+
b'thelongvalue62'
64+
b'thelongvalue63'
65+
b'thelongvalue64'
66+
b'thelongvalue65'
67+
b'thelongvalue66'
68+
b'thelongvalue67'
69+
b'thelongvalue68'
70+
b'thelongvalue69'
71+
b'thelongvalue70'
72+
b'thelongvalue71'
73+
b'thelongvalue72'
74+
b'thelongvalue73'
75+
b'thelongvalue74'
76+
b'thelongvalue75'
77+
b'thelongvalue76'
78+
b'thelongvalue77'
79+
b'thelongvalue78'
80+
b'thelongvalue79'

0 commit comments

Comments
 (0)