Adaptive Framework  0.9.0
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
afw_lmdb_adaptor.c
Go to the documentation of this file.
1 // See the 'COPYING' file in the project root for licensing information.
2 /*
3  * Implementation of afw_adaptor interface for LMDB
4  *
5  * Copyright (c) 2010-2023 Clemson University
6  *
7  */
8 
9 
15 #include "afw.h"
17 #include "afw_lmdb.h"
18 #include "afw_lmdb_internal.h"
19 #include "afw_lmdb_metadata.h"
20 #include "afw_lmdb_index.h"
21 #include "afw_adaptor_impl.h"
22 #include "afw_adaptor_impl_index.h"
23 
24 /* Declares and rti/inf defines for interface afw_adaptor */
25 #define AFW_IMPLEMENTATION_ID "lmdb"
27 
28 /*
29  * This routine loads the LMDB Adaptor's internal configuration object.
30  */
31 void afw_lmdb_adaptor_load_configuration(
32  afw_lmdb_adaptor_t * self,
33  const afw_pool_t *p,
34  afw_xctx_t *xctx)
35 {
36  MDB_txn *txn;
37  const afw_object_t *config;
38  int rc;
39 
40  rc = mdb_txn_begin(self->dbEnv, NULL, 0, &txn);
41  if (rc) {
42  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
43  "Unable to begin initial transaction.", xctx);
44  }
45 
46  config = afw_lmdb_internal_get_config(self, txn, p, xctx);
47 
48  self->internalConfig = afw_object_create_clone(
49  config, p, xctx);
50 
51  afw_lmdb_internal_save_config(self, self->internalConfig, txn, xctx);
52 
53  rc = mdb_txn_commit(txn);
54  if (rc) {
55  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
56  "Unable to commit initial transaction.", xctx);
57  }
58 }
59 
60 /*
61  *
62  */
63 const afw_lmdb_env_t * afw_lmdb_adaptor_parse_env(
64  const afw_object_t *envObject,
65  const afw_pool_t *p,
66  afw_xctx_t *xctx)
67 {
68  afw_lmdb_env_t *env;
69  const afw_value_t *value;
70 
72 
73  value = afw_object_get_property(envObject, &afw_lmdb_s_path, xctx);
74  if (!value) {
75  AFW_THROW_ERROR_Z(general,
76  "Property env.path required by LMDB adaptor.", xctx);
77  }
78  env->path_z = afw_value_as_utf8_z(value, p, xctx);
79 
80  value = afw_object_get_property(envObject, &afw_lmdb_s_mode, xctx);
81  if (!value) {
82  AFW_THROW_ERROR_Z(general,
83  "Property env.mode required by LMDB adaptor.", xctx);
84  }
85  env->mode = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
86 
87  value = afw_object_get_property(envObject, &afw_lmdb_s_maxreaders, xctx);
88  if (value) {
89  env->maxreaders = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
90  } else {
91  env->maxreaders = 0;
92  }
93 
94  value = afw_object_get_property(envObject, &afw_lmdb_s_maxdbs, xctx);
95  if (value) {
96  env->maxdbs = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
97  } else {
98  env->maxdbs = 0;
99  }
100 
101  value = afw_object_get_property(envObject, &afw_lmdb_s_mapsize, xctx);
102  if (value) {
103  env->mapsize = (size_t)afw_value_as_integer(value, xctx);
104  } else {
105  env->mapsize = 0;
106  }
107 
108  return env;
109 }
110 
111 const afw_lmdb_limits_t * afw_lmdb_adaptor_parse_limits(
112  const afw_object_t *lim, afw_xctx_t *xctx)
113 {
114  afw_lmdb_limits_t *limits;
115  const afw_object_t *obj;
116  const afw_value_t *value;
117 
118  limits = afw_xctx_calloc_type(afw_lmdb_limits_t, xctx);
119 
120  value = afw_object_get_property(lim, &afw_lmdb_s_size, xctx);
121  if (value) {
122  obj = afw_value_as_object(value, xctx);
123 
124  value = afw_object_get_property(obj, &afw_lmdb_s_soft, xctx);
125  if (value)
126  limits->size_soft = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
127  else
128  limits->size_soft = 500;
129 
130  value = afw_object_get_property(obj, &afw_lmdb_s_hard, xctx);
131  if (value)
132  limits->size_hard = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
133  else
134  limits->size_hard = 1000;
135  }
136 
137  value = afw_object_get_property(lim, &afw_lmdb_s_time, xctx);
138  if (value) {
139  obj = afw_value_as_object(value, xctx);
140 
141  value = afw_object_get_property(obj, &afw_lmdb_s_soft, xctx);
142  if (value)
143  limits->time_soft = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
144  else
145  limits->time_soft = 3600;
146 
147  value = afw_object_get_property(obj, &afw_lmdb_s_hard, xctx);
148  if (value)
149  limits->time_hard = afw_safe_cast_integer_to_int(afw_value_as_integer(value, xctx), xctx);
150  else
151  limits->time_hard = 14400;
152  }
153 
154  return limits;
155 }
156 
157 /*
158  * The LMDB API to open a database is mdb_dbi_open().
159  *
160  * According to the documentation, this function must not be
161  * called from multiple concurrent transactions in the same
162  * process. One way to make this easy is to go ahead and
163  * open all the databases we think we will need ahead of time.
164  *
165  */
167  afw_lmdb_adaptor_t * self,
168  const afw_pool_t * pool,
169  afw_xctx_t * xctx)
170 {
171  const afw_adaptor_impl_index_t *indexer;
172  const afw_object_t *indexDefinitions;
173  MDB_txn *txn;
174  int rc;
175 
176  rc = mdb_txn_begin(self->dbEnv, NULL, 0, &txn);
177  if (rc) {
178  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
179  "Unable to begin initial transaction.", xctx);
180  }
181 
182  /* first, open our "root" database, which is really only used for metrics */
184  //afw_lmdb_internal_open_database(self, txn,
185  // NULL, MDB_CREATE, pool, xctx);
186 
187  /* open the Primary database */
188  afw_lmdb_internal_open_database(self, txn,
189  &afw_lmdb_s_Primary, MDB_CREATE, pool, xctx);
190 
191  /* open the Journal database */
192  afw_lmdb_internal_open_database(self, txn,
193  &afw_lmdb_s_Journal, MDB_CREATE, pool, xctx);
194 
195  indexer = afw_lmdb_adaptor_impl_index_create(NULL, self, txn, xctx);
196 
197  /* now open up any index databases we may have */
198  indexDefinitions = afw_object_old_get_property_as_object(
199  self->internalConfig, &afw_lmdb_s_indexDefinitions, xctx);
200  if (indexDefinitions) {
201  afw_adaptor_impl_index_open_definitions(indexer,
202  indexDefinitions, pool, xctx);
203  }
204 
207  rc = mdb_txn_commit(txn);
208  if (rc) {
209  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
210  "Unable to commit initial transaction.", xctx);
211  }
212 }
213 
215  const afw_object_t *properties,
216  const afw_pool_t *p, afw_xctx_t *xctx)
217 {
218  afw_lmdb_adaptor_t *self;
219  afw_adaptor_t *adaptor;
220  const afw_value_t *value;
221  const afw_object_t *env;
222  const afw_object_t *limits;
223  int rc;
224  int deadReaders;
225 
226  /* Create adaptor and process common properties */
228  &impl_afw_adaptor_inf,
229  sizeof(afw_lmdb_adaptor_t),
230  properties, p, xctx);
231  self = (afw_lmdb_adaptor_t *)adaptor;
232 
233  /* This adaptor will always use the UBJSON content type */
234  self->ubjson = afw_environment_get_content_type(
235  &afw_s_ubjson, xctx);
236  if (!self->ubjson)
237  {
238  AFW_THROW_ERROR_Z(general,
239  "Unable to load UBJSON content-type", xctx);
240  }
241 
242  /* Get our env parameters */
243  value = afw_object_get_property(properties, &afw_lmdb_s_env, xctx);
244  if (!value) {
245  AFW_THROW_ERROR_Z(general,
246  "Property env required by LMDB adaptor.", xctx);
247  }
248  env = afw_value_as_object(value, xctx);
249 
250  self->env = afw_lmdb_adaptor_parse_env(env, p, xctx);
251 
252  /* create our LMDB environment */
253  rc = mdb_env_create(&self->dbEnv);
254  if (rc) {
255  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
256  "Unable to initialize LMDB environment.", xctx);
257  }
258 
259  /* set our maxdb's */
260  if (self->env->maxdbs)
261  mdb_env_set_maxdbs(self->dbEnv, self->env->maxdbs);
262  else
263  mdb_env_set_maxdbs(self->dbEnv, 128);
264 
265  /* set our maxreaders */
266  if (self->env->maxreaders)
267  mdb_env_set_maxreaders(self->dbEnv, self->env->maxreaders);
268 
269  /* set our mapsize */
270  if (self->env->mapsize)
271  mdb_env_set_mapsize(self->dbEnv, self->env->mapsize);
272 
273  /*
274  See: https://github.com/BVLC/caffe/issues/2404
275 
276  To make valgrind happy, our mapsize must fit inside physical
277  memory. Otherwise, the previous call will fail.
278 
279  If using valgrind, compile with -DVALGRIND
280  */
281 #ifdef VALGRIND
282  mdb_env_set_mapsize(self->dbEnv,
283  (self->env->mapsize && (self->env->mapsize < 7438953472) ?
284  self->env->mapsize : 7438953472));
285 #endif
286 
287  /* Now, open our LMDB environment */
288  rc = mdb_env_open(self->dbEnv, self->env->path_z, 0, self->env->mode);
289  if (rc) {
290  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
291  "Unable to open LMDB environment. Check path and permissions.",
292  xctx);
293  }
294 
295  /*
296  If multiple processes have the same LMDB environment open, then readers
297  can accumulate. This routine checks for stale readers and cleans them
298  up, if they are no longer in use.
299  */
300  rc = mdb_reader_check(self->dbEnv, &deadReaders);
301 
302  value = afw_object_get_property(properties, &afw_lmdb_s_limits, xctx);
303  if (value) {
304  limits = afw_value_as_object(value, xctx);
305  self->limits = afw_lmdb_adaptor_parse_limits(limits, xctx);
306  }
307 
308  /* Load metadata. */
309  afw_lmdb_metadata_refresh(self, xctx);
310 
311  /*
312  Create a database reader/writer lock, so transactions do not interfere
313  if we need to open a database in the future, that we haven't already
314  opened.
315  */
316  apr_thread_rwlock_create(&self->dbLock, afw_pool_get_apr_pool(p));
317 
318  /* create our dbi_handles */
319  self->dbi_handles = apr_hash_make(afw_pool_get_apr_pool(p));
320 
321  /* load our internal configuration object */
322  afw_lmdb_adaptor_load_configuration(self, p, xctx);
323 
324  /* Pre-open any databases we will need */
325  afw_lmdb_adaptor_open_databases(self, p, xctx);
326 
327  /* Return adaptor. */
328  return (const afw_adaptor_t *)self;
329 }
330 
331 
332 
333 /*
334  * Implementation of method destroy of interface afw_adaptor.
335  */
336 void
338  const afw_adaptor_t * instance,
339  afw_xctx_t *xctx)
340 {
341  afw_lmdb_adaptor_t *self = (afw_lmdb_adaptor_t *) instance;
342  apr_hash_index_t *hi;
343 
344  /* close any open databases */
345  for (hi = apr_hash_first(NULL, self->dbi_handles);
346  hi; hi = apr_hash_next(hi)) {
347  const char *k;
348  afw_lmdb_dbi_t *v;
349 
350  apr_hash_this(hi, (const void **)&k, NULL, (void**)&v);
351  mdb_dbi_close(self->dbEnv, v->dbi);
352  }
353 
354  /* release our database reader/writer lock */
355  apr_thread_rwlock_destroy(self->dbLock);
356 
357  /* close our LMDB environment */
358  mdb_env_close(self->dbEnv);
359 
360  /* Release pool. */
361  afw_pool_release(instance->p, xctx);
362 }
363 
364 
365 
366 /*
367  * Implementation of method create_adaptor_session of interface afw_adaptor.
368  */
369 const afw_adaptor_session_t *
371  const afw_adaptor_t * instance,
372  afw_xctx_t *xctx)
373 {
374  afw_lmdb_adaptor_t *self = (afw_lmdb_adaptor_t *)instance;
375 
376  return (const afw_adaptor_session_t *)
378 }
379 
380 
381 /*
382  * Implementation of method get_additional_metrics of interface afw_adaptor.
383  */
384 const afw_object_t *
386  const afw_adaptor_t * instance,
387  const afw_pool_t * p,
388  afw_xctx_t *xctx)
389 {
390  const afw_lmdb_adaptor_t *self =
391  (afw_lmdb_adaptor_t *) instance;
392  int major, minor, patch;
393  char *version_str;
394  const afw_object_t *metrics;
395  const afw_object_t *version;
396  const afw_object_t *statistics;
397  const afw_object_t *information;
398  const afw_object_t *environment;
399  const afw_object_t *database;
400  MDB_stat stat;
401  MDB_envinfo info;
402  MDB_dbi dbi;
403  MDB_txn *txn;
404  int rc;
405 
406  /* Create additional metrics object and set object type. */
407  metrics = afw_object_create_managed(p, xctx);
409  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb,
410  xctx);
411 
438  /* create our version object, which reports LMDB version information */
439  version = afw_object_create_embedded(metrics,
440  &afw_lmdb_s_version, xctx);
441 
443  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb_version,
444  xctx);
445 
446  version_str = mdb_version(&major, &minor, &patch);
447  if (version_str) {
449  &afw_lmdb_s_version_string, version_str, xctx);
450  afw_object_set_property(version, &afw_lmdb_s_major,
451  afw_value_create_integer(major, p, xctx), xctx);
452  afw_object_set_property(version, &afw_lmdb_s_minor,
453  afw_value_create_integer(minor, p, xctx), xctx);
454  afw_object_set_property(version, &afw_lmdb_s_patch,
455  afw_value_create_integer(patch, p, xctx), xctx);
456  }
457 
458  /* gather statistics for each database */
459  statistics = afw_object_create_embedded(metrics,
460  &afw_lmdb_s_statistics, xctx);
461 
463  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb_statistics,
464  xctx);
465 
466  /* start with the environment stats */
467  environment = afw_object_create_embedded(statistics,
468  &afw_lmdb_s_environment, xctx);
469 
471  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb_statistic,
472  xctx);
473 
474  rc = mdb_env_stat(self->dbEnv, &stat);
475  if (rc == 0) {
476  afw_object_set_property(environment, &afw_lmdb_s_psize,
477  afw_value_create_integer(stat.ms_psize, p, xctx), xctx);
478  afw_object_set_property(environment, &afw_lmdb_s_depth,
479  afw_value_create_integer(stat.ms_depth, p, xctx), xctx);
480  afw_object_set_property(environment, &afw_lmdb_s_branch_pages,
481  afw_value_create_integer(stat.ms_branch_pages, p, xctx), xctx);
482  afw_object_set_property(environment, &afw_lmdb_s_leaf_pages,
483  afw_value_create_integer(stat.ms_leaf_pages, p, xctx), xctx);
484  afw_object_set_property(environment, &afw_lmdb_s_overflow_pages,
485  afw_value_create_integer(stat.ms_overflow_pages, p, xctx), xctx);
486  afw_object_set_property(environment, &afw_lmdb_s_entries,
487  afw_value_create_integer(stat.ms_entries, p, xctx), xctx);
488  }
489 
490  /* gather the env_info */
491  information = afw_object_create_embedded(metrics,
492  &afw_lmdb_s_information, xctx);
493 
495  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb_information,
496  xctx);
497 
498  rc = mdb_env_info(self->dbEnv, &info);
499  if (rc == 0) {
500  afw_object_set_property(information, &afw_lmdb_s_mapaddr,
501  afw_value_create_integer((size_t)info.me_mapaddr, p, xctx), xctx);
502  afw_object_set_property(information, &afw_lmdb_s_mapsize,
503  afw_value_create_integer(info.me_mapsize, p, xctx), xctx);
504  afw_object_set_property(information, &afw_lmdb_s_last_pgno,
505  afw_value_create_integer(info.me_last_pgno, p, xctx), xctx);
506  afw_object_set_property(information, &afw_lmdb_s_last_txnid,
507  afw_value_create_integer(info.me_last_txnid, p, xctx), xctx);
508  afw_object_set_property(information, &afw_lmdb_s_maxreaders,
509  afw_value_create_integer(info.me_maxreaders, p, xctx), xctx);
510  afw_object_set_property(information, &afw_lmdb_s_numreaders,
511  afw_value_create_integer(info.me_numreaders, p, xctx), xctx);
512  }
513 
514  apr_thread_rwlock_rdlock(self->dbLock);
515 
516  rc = mdb_txn_begin(self->dbEnv, NULL, 0, &txn);
517  if (rc) {
518  apr_thread_rwlock_unlock(self->dbLock);
519 
520  AFW_THROW_ERROR_RV_Z(general, lmdb, rc,
521  "Unable to begin initial transaction.", xctx);
522  }
523 
524  rc = mdb_dbi_open(txn, NULL, 0, &dbi);
525  if (rc == 0) {
526  MDB_cursor *cursor;
527  MDB_val key;
528  const afw_utf8_t *database_str;
529 
530  rc = mdb_cursor_open(txn, dbi, &cursor);
531  if (rc == 0) {
532  while ((rc = mdb_cursor_get(cursor, &key, NULL, MDB_NEXT_NODUP)) == 0)
533  {
534  char *str;
535  MDB_dbi db2;
536  if (memchr(key.mv_data, '\0', key.mv_size))
537  continue;
538  str = afw_pool_malloc(p, key.mv_size+1, xctx);
539  memcpy(str, key.mv_data, key.mv_size);
540  str[key.mv_size] = '\0';
541 
542  database_str = afw_utf8_create(str, key.mv_size, p, xctx);
543 
544  db2 = afw_lmdb_internal_open_database(self,
545  txn, database_str, 0, p, xctx);
546  if (db2 == 0) continue;
547 
548  rc = mdb_stat(txn, db2, &stat);
549  if (rc == 0) {
550  database = afw_object_create_embedded(statistics,
551  database_str, xctx);
552 
554  &afw_lmdb_s__AdaptiveAdaptorMetrics_adaptor_lmdb_statistic,
555  xctx);
556 
557  afw_object_set_property(database, &afw_lmdb_s_psize,
558  afw_value_create_integer(stat.ms_psize, p, xctx), xctx);
559  afw_object_set_property(database, &afw_lmdb_s_depth,
560  afw_value_create_integer(stat.ms_depth, p, xctx), xctx);
561  afw_object_set_property(database, &afw_lmdb_s_branch_pages,
562  afw_value_create_integer(stat.ms_branch_pages, p, xctx), xctx);
563  afw_object_set_property(database, &afw_lmdb_s_leaf_pages,
564  afw_value_create_integer(stat.ms_leaf_pages, p, xctx), xctx);
565  afw_object_set_property(database, &afw_lmdb_s_overflow_pages,
566  afw_value_create_integer(stat.ms_overflow_pages, p, xctx), xctx);
567  afw_object_set_property(database, &afw_lmdb_s_entries,
568  afw_value_create_integer(stat.ms_entries, p, xctx), xctx);
569  }
570  }
571 
572  mdb_cursor_close(cursor);
573  }
574 
575  mdb_close(self->dbEnv, dbi);
576  }
577 
578  rc = mdb_txn_commit(txn);
579 
580  apr_thread_rwlock_unlock(self->dbLock);
581 
582  return metrics;
583 }
Adaptive Framework Core API.
Helpers for adaptor implementation development.
Interface afw_interface implementation declares.
Helpers for afw_adaptor implementation index development.
Adaptive Framework LMDB Adaptor.
void afw_lmdb_adaptor_open_databases(afw_lmdb_adaptor_t *self, const afw_pool_t *pool, afw_xctx_t *xctx)
const afw_adaptor_t * afw_lmdb_adaptor_create_cede_p(const afw_object_t *properties, const afw_pool_t *p, afw_xctx_t *xctx)
Internal create an LMDB adaptor.
afw_lmdb_adaptor_session_t * afw_lmdb_adaptor_session_create(afw_lmdb_adaptor_t *adaptor, afw_xctx_t *xctx)
Internal create a LMDB adaptor session.
Adaptive Framework register generated (afw_lmdb) header.
Helpers for afw_adaptor implementation index development.
Adaptive Framework LMDB Adaptor Internal Header.
Adaptive Framework LMDB Adaptor Metadata handler.
void afw_lmdb_metadata_refresh(afw_lmdb_adaptor_t *adaptor, afw_xctx_t *xctx)
Refreshes LMDB adaptors Metadata.
const afw_object_t * impl_afw_adaptor_get_additional_metrics(const afw_adaptor_t *instance, const afw_pool_t *p, afw_xctx_t *xctx)
void impl_afw_adaptor_destroy(const afw_adaptor_t *instance, afw_xctx_t *xctx)
const afw_adaptor_session_t * impl_afw_adaptor_create_adaptor_session(const afw_adaptor_t *instance, afw_xctx_t *xctx)
afw_adaptor_impl_create_cede_p(const afw_adaptor_inf_t *inf, afw_size_t instance_size, const afw_object_t *properties, const afw_pool_t *p, afw_xctx_t *xctx)
Developers should call this in all create functions for afw_adaptor.
afw_value_create_integer(afw_integer_t internal, const afw_pool_t *p, afw_xctx_t *xctx)
Create function for unmanaged data type integer value.
afw_value_as_integer(const afw_value_t *value, afw_xctx_t *xctx)
Typesafe cast of data type integer.
#define afw_object_old_get_property_as_object(object, property_name, xctx)
Get property function for data type object value.
afw_value_as_object(const afw_value_t *value, afw_xctx_t *xctx)
Typesafe cast of data type object.
const afw_content_type_t * afw_environment_get_content_type(const afw_utf8_t *type, afw_xctx_t *xctx)
Get the afw_content_type struct associated with a content type.
#define AFW_THROW_ERROR_RV_Z(code, rv_source_id, rv, message_z, xctx)
Macro used to set error and rv in xctx and throw it.
Definition: afw_error.h:301
#define AFW_THROW_ERROR_Z(code, message_z, xctx)
Macro used to set error and 0 rv in xctx and throw it.
Definition: afw_error.h:283
#define afw_object_get_property(instance, property_name, xctx)
Call method get_property of interface afw_object.
afw_object_meta_set_object_type_id(const afw_object_t *instance, const afw_utf8_t *object_type_id, afw_xctx_t *xctx)
Set object's object type id.
afw_object_create_clone(const afw_object_t *object, const afw_pool_t *p, afw_xctx_t *xctx)
Clone an object to a specified pool.
Definition: afw_memory.c:138
#define afw_object_create_managed(p, xctx)
Create an empty entity object in its own pool.
Definition: afw_object.h:913
afw_object_set_property_as_string_from_utf8_z(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_utf8_z_t *string_z, afw_xctx_t *xctx)
Set an string property from utf8_z.
Definition: afw_object.c:194
afw_object_set_property(const afw_object_t *instance, const afw_utf8_t *property_name, const afw_value_t *value, afw_xctx_t *xctx)
Set the value of an object's property.
Definition: afw_object.c:46
const afw_object_t * afw_object_create_embedded(const afw_object_t *embedding_object, const afw_utf8_t *property_name, afw_xctx_t *xctx)
Create an empty embedded object in a memory object.
#define afw_pool_malloc(instance, size, xctx)
Call method malloc of interface afw_pool.
#define afw_pool_get_apr_pool(instance)
Call method get_apr_pool of interface afw_pool.
#define afw_pool_release(instance, xctx)
Call method release of interface afw_pool.
int afw_safe_cast_integer_to_int(afw_integer_t integer, afw_xctx_t *xctx)
Safely cast afw_integer_t to int.
Definition: afw_safe_cast.h:89
#define afw_utf8_create(s, len, p, xctx)
Create utf-8 string without copy unless necessary in pool specified.
Definition: afw_utf8.h:239
afw_value_as_utf8_z(const afw_value_t *value, const afw_pool_t *p, afw_xctx_t *xctx)
Definition: afw_value.c:315
#define afw_xctx_calloc_type(type, xctx)
Macro to allocate cleared memory to hold type in xctx's pool.
Definition: afw_xctx.h:199
Interface afw_adaptor_impl_index public struct.
Interface afw_adaptor public struct.
Interface afw_adaptor_session public struct.
Interface afw_object public struct.
Interface afw_pool public struct.
NFC normalized UTF-8 string.
Definition: afw_common.h:545
Interface afw_value public struct.
Interface afw_xctx public struct.