Skip to content

Commit f7a2523

Browse files
committed
Define custom memory allocation definitions
What my aim here is to expose the amount of memory being utilized by an erlang process that is currently running.
1 parent ed06682 commit f7a2523

File tree

1 file changed

+108
-13
lines changed

1 file changed

+108
-13
lines changed

c_src/sqlite3_nif.c

Lines changed: 108 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,83 @@ typedef struct statement
2323
sqlite3_stmt* statement;
2424
} statement_t;
2525

26+
static void*
27+
exqlite_malloc(int bytes)
28+
{
29+
assert(bytes > 0);
30+
31+
int* p = enif_alloc(bytes + sizeof(int));
32+
if (p) {
33+
p[0] = bytes;
34+
p++;
35+
}
36+
37+
return p;
38+
}
39+
40+
static void
41+
exqlite_free(void* prior)
42+
{
43+
if (!prior) {
44+
return;
45+
}
46+
47+
int* p = prior;
48+
49+
// Shift the pointer back to free the proper block of data
50+
p--;
51+
52+
return enif_free(p);
53+
}
54+
55+
static void*
56+
exqlite_realloc(void* prior, int bytes)
57+
{
58+
assert(prior);
59+
assert(bytes > 0);
60+
61+
int* p = prior;
62+
p--;
63+
64+
p = enif_realloc(p, bytes + sizeof(int));
65+
if (p) {
66+
p[0] = bytes;
67+
p++;
68+
}
69+
70+
return p;
71+
}
72+
73+
static int
74+
exqlite_mem_size(void* prior)
75+
{
76+
if (!prior) {
77+
return 0;
78+
}
79+
80+
int* p = prior;
81+
p--;
82+
83+
return p[0];
84+
}
85+
86+
static int
87+
exqlite_mem_round_up(int bytes)
88+
{
89+
return (bytes + 7) & ~7;
90+
}
91+
92+
static int
93+
exqlite_mem_init(void* ptr)
94+
{
95+
return SQLITE_OK;
96+
}
97+
98+
static void
99+
exqlite_mem_shutdown(void* ptr)
100+
{
101+
}
102+
26103
static const char*
27104
get_sqlite3_error_msg(int rc, sqlite3* db)
28105
{
@@ -496,7 +573,7 @@ exqlite_multi_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
496573
return enif_make_tuple2(env, make_atom(env, "done"), rows);
497574

498575
case SQLITE_ROW:
499-
row = make_row(env, statement->statement);
576+
row = make_row(env, statement->statement);
500577
rows = enif_make_list_cell(env, row, rows);
501578
break;
502579

@@ -533,10 +610,9 @@ exqlite_step(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
533610
switch (rc) {
534611
case SQLITE_ROW:
535612
return enif_make_tuple2(
536-
env,
537-
make_atom(env, "row"),
538-
make_row(env, statement->statement)
539-
);
613+
env,
614+
make_atom(env, "row"),
615+
make_row(env, statement->statement));
540616
case SQLITE_BUSY:
541617
return make_atom(env, "busy");
542618
case SQLITE_DONE:
@@ -651,8 +727,8 @@ exqlite_serialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
651727

652728
connection_t* conn = NULL;
653729
ErlNifBinary database_name;
654-
ERL_NIF_TERM eos = enif_make_int(env, 0);
655-
unsigned char* buffer = NULL;
730+
ERL_NIF_TERM eos = enif_make_int(env, 0);
731+
unsigned char* buffer = NULL;
656732
sqlite3_int64 buffer_size = 0;
657733
ERL_NIF_TERM serialized;
658734

@@ -668,7 +744,7 @@ exqlite_serialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
668744
return make_error_tuple(env, "database_name_not_iolist");
669745
}
670746

671-
buffer = sqlite3_serialize(conn->db, (char*) database_name.data, &buffer_size, 0);
747+
buffer = sqlite3_serialize(conn->db, (char*)database_name.data, &buffer_size, 0);
672748
if (!buffer) {
673749
return make_error_tuple(env, "serialization_failed");
674750
}
@@ -684,13 +760,13 @@ exqlite_deserialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
684760
{
685761
assert(env);
686762

687-
connection_t* conn = NULL;
763+
connection_t* conn = NULL;
688764
unsigned char* buffer = NULL;
689765
ErlNifBinary database_name;
690766
ERL_NIF_TERM eos = enif_make_int(env, 0);
691767
ErlNifBinary serialized;
692-
int size = 0;
693-
int rc = 0;
768+
int size = 0;
769+
int rc = 0;
694770
int flags = SQLITE_DESERIALIZE_FREEONCLOSE | SQLITE_DESERIALIZE_RESIZEABLE;
695771

696772
if (argc != 3) {
@@ -709,7 +785,7 @@ exqlite_deserialize(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
709785
return enif_make_badarg(env);
710786
}
711787

712-
size = serialized.size;
788+
size = serialized.size;
713789
buffer = sqlite3_malloc(size);
714790
if (!buffer) {
715791
return make_error_tuple(env, "deserialization_failed");
@@ -785,6 +861,18 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
785861
{
786862
assert(env);
787863

864+
static const sqlite3_mem_methods methods = {
865+
exqlite_malloc,
866+
exqlite_free,
867+
exqlite_realloc,
868+
exqlite_mem_size,
869+
exqlite_mem_round_up,
870+
exqlite_mem_init,
871+
exqlite_mem_shutdown,
872+
0};
873+
874+
sqlite3_config(SQLITE_CONFIG_MALLOC, &methods);
875+
788876
connection_type = enif_open_resource_type(
789877
env,
790878
"exqlite",
@@ -810,6 +898,13 @@ on_load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
810898
return 0;
811899
}
812900

901+
static void
902+
on_unload(ErlNifEnv* caller_env, void* priv_data)
903+
{
904+
assert(env);
905+
906+
sqlite3_config(SQLITE_CONFIG_MALLOC, NULL);
907+
}
813908

814909
//
815910
// Enable extension loading
@@ -870,4 +965,4 @@ static ErlNifFunc nif_funcs[] = {
870965
#define ERL_NIF_INIT_DECL(MODNAME) ErlNifEntry* sqlite3_nif_nif_init(ERL_NIF_INIT_ARGS)
871966
#endif
872967

873-
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, NULL)
968+
ERL_NIF_INIT(Elixir.Exqlite.Sqlite3NIF, nif_funcs, on_load, NULL, NULL, on_unload)

0 commit comments

Comments
 (0)