mdb_layer.c 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2020 Red Hat, Inc.
  3. * All rights reserved.
  4. *
  5. * License: GPL (version 3 or any later version).
  6. * See LICENSE for details.
  7. * END COPYRIGHT BLOCK **/
  8. #ifdef HAVE_CONFIG_H
  9. #include <config.h>
  10. #endif
  11. #include <unistd.h>
  12. #include "mdb_layer.h"
  13. #include <prthread.h>
  14. #include <prclist.h>
  15. #include <sys/types.h>
  16. #include <sys/statvfs.h>
  17. #include <glob.h>
  18. Slapi_ComponentId *dbmdb_componentid;
  19. #define BULKOP_MAX_RECORDS 100 /* Max records handled by a single bulk operations */
  20. #define RECNO_CACHE_INTERVAL 1000 /* 1 key added in cache for every RECNO_CACHE_INTERVAL vlv keys */
  21. /* bulkdata->v.data contents */
  22. typedef struct {
  23. int use_multiple; /* If if we use GET_MULTIPLE/NEXT_MULTIPLE or use single operation method */
  24. uint dbi_flags; /* dbi flags */
  25. MDB_cursor *cursor; /* cursor position */
  26. int op; /* MDB operation to get next value */
  27. int maxrecords; /* Number maximum of operation before moving to next block */
  28. MDB_val data0; /* data got when setting the cursor */
  29. MDB_val data; /* data for single or multiple operation */
  30. MDB_val key; /* key */
  31. size_t data_size; /* Size of a single item in data */
  32. } dbmdb_bulkdata_t;
  33. /* Use these macros to incr/decrement the thread count for the
  34. database housekeeping threads. This ensures that the
  35. value is changed in a thread safe manner, and safely notifies
  36. the main thread during cleanup. INCR_THREAD_COUNT should be
  37. the first real statement in the thread function, before any
  38. actual work is done, other than perhaps variable assignments.
  39. DECR_THREAD_COUNT should be called as the next to last thing
  40. in the thread function, just before the trace log message and
  41. return.
  42. */
  43. #define INCR_THREAD_COUNT(pEnv) \
  44. pthread_mutex_lock(&pEnv->dbmdb_thread_count_lock); \
  45. ++pEnv->dbmdb_thread_count; \
  46. pthread_mutex_unlock(&pEnv->dbmdb_thread_count_lock)
  47. #define DECR_THREAD_COUNT(pEnv) \
  48. pthread_mutex_lock(&pEnv->dbmdb_thread_count_lock); \
  49. if (--pEnv->dbmdb_thread_count == 0) { \
  50. pthread_cond_broadcast(&pEnv->dbmdb_thread_count_cv); \
  51. } \
  52. pthread_mutex_unlock(&pEnv->dbmdb_thread_count_lock)
  53. #define NEWDIR_MODE 0755
  54. #define DB_REGION_PREFIX "__db."
  55. static int dbmdb_force_checkpoint(struct ldbminfo *li);
  56. #define MEGABYTE (1024 * 1024)
  57. #define GIGABYTE (1024 * MEGABYTE)
  58. /* env. vars. you can set to stress txn handling */
  59. #define TXN_TESTING "TXN_TESTING" /* enables the txn test thread */
  60. #define TXN_TEST_HOLD_MSEC "TXN_TEST_HOLD_MSEC" /* time to hold open the db cursors */
  61. #define TXN_TEST_LOOP_MSEC "TXN_TEST_LOOP_MSEC" /* time to wait before looping again */
  62. #define TXN_TEST_USE_TXN "TXN_TEST_USE_TXN" /* use transactions or not */
  63. #define TXN_TEST_USE_RMW "TXN_TEST_USE_RMW" /* use DB_RMW for c_get flags or not */
  64. #define TXN_TEST_INDEXES "TXN_TEST_INDEXES" /* list of indexes to use - comma delimited - id2entry,entryrdn,etc. */
  65. #define TXN_TEST_VERBOSE "TXN_TEST_VERBOSE" /* be wordy */
  66. /* this flag is used if user remotely turned batching off */
  67. #define FLUSH_REMOTEOFF 0
  68. static const char *backupfilelists[] = { INFOFILE, DBMAPFILE, DSE_INSTANCE, DSE_INDEX, NULL };
  69. /*
  70. * return nsslapd-db-home-directory (dbmdb_dbhome_directory), if exists.
  71. * Otherwise, return nsslapd-directory (dbmdb_home_directory).
  72. *
  73. * if dbmdb_dbhome_directory exists, set 1 to dbhome.
  74. */
  75. char *
  76. dbmdb_get_home_dir(struct ldbminfo *li, int *dbhome)
  77. {
  78. dbmdb_ctx_t *conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  79. if (conf->home[0]) {
  80. *dbhome = 1;
  81. return conf->home;
  82. }
  83. slapi_log_err(SLAPI_LOG_WARNING, "dbmdb_get_home_dir", "Db home directory is not set. "
  84. "Possibly %s (optionally %s) is missing in the config file.\n",
  85. CONFIG_DIRECTORY, CONFIG_DB_HOME_DIRECTORY);
  86. return NULL;
  87. }
  88. /*
  89. * return the top db directory
  90. */
  91. char *
  92. dbmdb_get_db_dir(struct ldbminfo *li)
  93. {
  94. return li->li_directory;
  95. }
  96. /* Function which calls limdb to override some system calls which
  97. * the library makes. We call this before calling any other function
  98. * in limdb.
  99. * Several OS use this, either partially or completely.
  100. * This will eventually change---we will simply pass to limdb
  101. * the addresses of a bunch of NSPR functions, and everything
  102. * will magically work on all platforms (Ha!)
  103. */
  104. #ifdef DB_USE_64LFS
  105. /* What is going on here ?
  106. * Well, some platforms now support an extended API for dealing with
  107. * files larger than 2G. (This apparently comes from the LFS -- "Large
  108. * File Summit"... Summit, indeed.) Anyway, we try to detect at runtime
  109. * whether this machine has the extended API, and use it if it's present.
  110. *
  111. */
  112. /* helper function for open64 */
  113. static int
  114. dbmdb_open_large(const char *path, int oflag, mode_t mode)
  115. {
  116. int err;
  117. err = open64(path, oflag, mode);
  118. /* weird but necessary: */
  119. if (err >= 0)
  120. errno = 0;
  121. return err;
  122. }
  123. /* this is REALLY dumb. but nspr 19980529(x) doesn't support 64-bit files
  124. * because of some weirdness we're doing at initialization (?), so we need
  125. * to export some function that can open huge files, so that exporting
  126. * can work right. when we fix the nspr problem (or get a more recent
  127. * version of nspr that might magically work?), this should be blown away.
  128. * (call mode_t an int because NT can't handle that in prototypes.)
  129. * -robey, 28oct98
  130. */
  131. int
  132. dbmdb_open_huge_file(const char *path, int oflag, int mode)
  133. {
  134. return dbmdb_open_large(path, oflag, (mode_t)mode);
  135. }
  136. #else /* DB_USE_64LFS */
  137. int
  138. dbmdb_open_huge_file(const char *path, int oflag, int mode)
  139. {
  140. return open(path, oflag, mode);
  141. }
  142. #endif /* DB_USE_64LFS */
  143. /*
  144. * This function is called after all the config options have been read in,
  145. * so we can do real initialization work here.
  146. */
  147. int
  148. dbmdb_start(struct ldbminfo *li, int dbmode)
  149. {
  150. int readonly = dbmode & (DBLAYER_ARCHIVE_MODE | DBLAYER_EXPORT_MODE | DBLAYER_TEST_MODE);
  151. int rc;
  152. dblayer_init_pvt_txn(); /* Initialize thread local storage for handling dblayer txn */
  153. rc = dbmdb_make_env(MDB_CONFIG(li), readonly, li->li_mode);
  154. if (rc == 0) {
  155. /* As indexes are DUPSORT db, index key + index data are limited
  156. * to mdb_env_get_maxkeysize(env) and indexes data are IDs
  157. * So we determine here the max key lenght
  158. */
  159. li->li_max_key_len = mdb_env_get_maxkeysize(MDB_CONFIG(li)->env) - sizeof (ID);
  160. }
  161. return rc;
  162. }
  163. /* mode is one of
  164. * DBLAYER_NORMAL_MODE,
  165. * DBLAYER_INDEX_MODE,
  166. * DBLAYER_IMPORT_MODE,
  167. * DBLAYER_EXPORT_MODE
  168. */
  169. int
  170. dbmdb_instance_start(backend *be, int mode)
  171. {
  172. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  173. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  174. dbmdb_ctx_t *ctx = MDB_CONFIG(li);
  175. int return_value = -1;
  176. dbmdb_dbi_t *id2entry_dbi = NULL;
  177. if (!ctx->env) {
  178. slapi_log_err(SLAPI_LOG_ERR,
  179. "dbmdb_instance_start", "Backend %s: dbenv is not available.\n",
  180. inst ? inst->inst_name : "unknown");
  181. return return_value;
  182. }
  183. /* Need to duplicate because ldbm_instance_destructor frees both values */
  184. slapi_ch_free_string(&inst->inst_dir_name);
  185. inst->inst_dir_name = slapi_ch_strdup(inst->inst_name);
  186. if (NULL != inst->inst_id2entry) {
  187. slapi_log_err(SLAPI_LOG_WARNING,
  188. "dbmdb_instance_start", "Backend \"%s\" already started.\n",
  189. inst->inst_name);
  190. return 0;
  191. }
  192. if (attrcrypt_init(inst)) {
  193. slapi_log_err(SLAPI_LOG_ERR,
  194. "dbmdb_instance_start", "Unable to initialize attrcrypt system for %s\n",
  195. inst->inst_name);
  196. return return_value;
  197. }
  198. /* Now attempt to open the instance files */
  199. return_value = dbmdb_open_all_files(ctx, be);
  200. if (return_value == 0) {
  201. id2entry_dbi = (dbmdb_dbi_t*)(inst->inst_id2entry);
  202. if ((mode & DBLAYER_NORMAL_MODE) && id2entry_dbi->state.dataversion != DBMDB_CURRENT_DATAVERSION) {
  203. return_value = dbmdb_ldbm_upgrade(inst, id2entry_dbi->state.dataversion);
  204. }
  205. }
  206. if (0 == return_value) {
  207. /* get nextid from disk now */
  208. get_ids_from_disk(be);
  209. }
  210. if (mode & DBLAYER_NORMAL_MODE) {
  211. /* richm - not sure if need to acquire the be lock first? */
  212. /* need to set state back to started - set to stopped in
  213. dblayer_instance_close */
  214. be->be_state = BE_STATE_STARTED;
  215. }
  216. /*
  217. * check if nextid is valid: it only matters if the database is either
  218. * being imported or is in normal mode
  219. */
  220. if (inst->inst_nextid > MAXID && !(mode & DBLAYER_EXPORT_MODE)) {
  221. slapi_log_err(SLAPI_LOG_CRIT, "dbmdb_instance_start", "Backend '%s' "
  222. "has no IDs left. DATABASE MUST BE REBUILT.\n",
  223. be->be_name);
  224. return 1;
  225. }
  226. if (return_value != 0) {
  227. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_instance_start", "Failure %s (%d)\n",
  228. dblayer_strerror(return_value), return_value);
  229. }
  230. return return_value;
  231. }
  232. void
  233. dbmdb_pre_close(struct ldbminfo *li)
  234. {
  235. /* There is no database threads ==> nothing to do */
  236. }
  237. int
  238. dbmdb_post_close(struct ldbminfo *li, int dbmode)
  239. {
  240. dbmdb_ctx_t *conf = 0;
  241. int return_value = 0;
  242. PR_ASSERT(NULL != li);
  243. dblayer_private *priv = li->li_dblayer_private;
  244. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  245. /* We close all the files we ever opened, and call pEnv->close. */
  246. if (NULL == conf->env) /* db env is already closed. do nothing. */
  247. return return_value;
  248. /* Shutdown the performance counter stuff */
  249. if (DBLAYER_NORMAL_MODE & dbmode) {
  250. dbmdb_perfctrs_terminate(conf);
  251. }
  252. /* Now release the db environment */
  253. dbmdb_ctx_close(conf);
  254. priv->dblayer_env = NULL;
  255. return return_value;
  256. }
  257. /*
  258. * This function is called when the server is shutting down, or when the
  259. * backend is being disabled (e.g. backup/restore).
  260. * This is not safe to call while other threads are calling into the open
  261. * databases !!! So: DON'T !
  262. */
  263. int
  264. dbmdb_close(struct ldbminfo *li, int dbmode)
  265. {
  266. backend *be = NULL;
  267. ldbm_instance *inst;
  268. Object *inst_obj;
  269. int return_value = 0;
  270. int shutdown = g_get_shutdown();
  271. dbmdb_pre_close(li);
  272. /*
  273. * dblayer_close_indexes and pDB->close used to be located above loop:
  274. * while(priv->dblayer_thread_count > 0) in pre_close.
  275. * This order fixes a bug: shutdown under the stress makes txn_checkpoint
  276. * (checkpoint_thread) fail b/c the mpool might have been already closed.
  277. */
  278. for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
  279. inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
  280. inst = (ldbm_instance *)object_get_data(inst_obj);
  281. if (shutdown) {
  282. vlv_close(inst);
  283. }
  284. be = inst->inst_be;
  285. if (NULL != be->be_instance_info) {
  286. return_value |= dblayer_instance_close(be);
  287. }
  288. }
  289. return_value |= dbmdb_post_close(li, dbmode);
  290. return return_value;
  291. }
  292. /* API to remove the environment */
  293. int
  294. dbmdb_remove_env(struct ldbminfo *li)
  295. {
  296. /* No removable env file with mdb */
  297. return 0;
  298. }
  299. /* Determine mdb open flags according to dbi type */
  300. int dbmdb_get_open_flags(const char *dbname)
  301. {
  302. const char *pt = strrchr(dbname, '/');
  303. if (!pt) {
  304. pt = dbname;
  305. }
  306. if (!strcasecmp(pt, LDBM_ENTRYRDN_STR LDBM_FILENAME_SUFFIX)) {
  307. return MDB_DUPSORT;
  308. }
  309. if (!strcasecmp(pt, ID2ENTRY LDBM_FILENAME_SUFFIX)) {
  310. return 0;
  311. }
  312. if (strstr(pt, "changelog")) {
  313. return 0;
  314. }
  315. /* Otherwise assume it is an index */
  316. return MDB_DUPSORT + MDB_INTEGERDUP + MDB_DUPFIXED;
  317. }
  318. /* Routines for opening and closing a db instance (MDB_dbi) in the MDB_env.
  319. Used by ldif2db merging code currently.
  320. Return value:
  321. Success: 0
  322. Failure: -1
  323. */
  324. int
  325. dbmdb_get_db(backend *be, char *indexname, int open_flag, struct attrinfo *ai, dbi_db_t **ppDB)
  326. {
  327. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  328. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  329. int open_flags = 0;
  330. dbmdb_cursor_t cur = {0};
  331. int return_value = 0;
  332. PR_ASSERT(NULL != li);
  333. PR_ASSERT(NULL != li->li_dblayer_private);
  334. *ppDB = NULL;
  335. if (NULL == inst->inst_name) {
  336. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_get_db", "Backend instance name is not configured.\n");
  337. return -1;
  338. }
  339. open_flags = 0;
  340. if (open_flag & MDB_OPEN_DIRTY_DBI)
  341. open_flags |= MDB_OPEN_DIRTY_DBI;
  342. if (open_flag & DBOPEN_CREATE)
  343. open_flags |= MDB_CREATE;
  344. if (open_flag & DBOPEN_TRUNCATE)
  345. open_flags |= MDB_TRUNCATE_DBI;
  346. if (open_flag & DBOPEN_ALLOW_DIRTY)
  347. open_flags |= MDB_OPEN_DIRTY_DBI;
  348. /* If import mode try to open in dirty mode */
  349. if (ai && (ai->ai_indexmask & INDEX_OFFLINE))
  350. open_flags |= MDB_OPEN_DIRTY_DBI;
  351. if (dbmdb_public_in_import(inst))
  352. open_flags |= MDB_OPEN_DIRTY_DBI;
  353. return_value = dbmdb_open_dbi_from_filename(&cur.dbi, be, indexname, ai, open_flags);
  354. if (0 != return_value)
  355. goto out;
  356. *ppDB = (dbi_db_t *)(cur.dbi);
  357. out:
  358. return return_value;
  359. }
  360. /*
  361. dbmdb_db_remove assumptions:
  362. No environment has the given database open.
  363. */
  364. #define DBLAYER_CACHE_DELAY PR_MillisecondsToInterval(5)
  365. int
  366. dbmdb_rm_db_file(backend *be, struct attrinfo *a, PRBool use_lock, int no_force_checkpoint)
  367. {
  368. struct ldbminfo *li = NULL;
  369. ldbm_instance *inst = NULL;
  370. dblayer_handle *handle = NULL;
  371. char *dbname = NULL;
  372. int rc = 0;
  373. dbi_db_t *db = 0;
  374. dbmdb_ctx_t *conf = NULL;
  375. if ((NULL == be) || (NULL == be->be_database)) {
  376. return rc;
  377. }
  378. inst = (ldbm_instance *)be->be_instance_info;
  379. if (NULL == inst) {
  380. return rc;
  381. }
  382. li = (struct ldbminfo *)be->be_database->plg_private;
  383. if (NULL == li) {
  384. return rc;
  385. }
  386. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  387. if (NULL == conf || NULL == conf->env) { /* db does not exist or not started */
  388. return rc;
  389. }
  390. if (0 == dblayer_get_index_file(be, a, (dbi_db_t**)&db, MDB_OPEN_DIRTY_DBI /* Don't create an index file
  391. if it does not exist but open dirty files. */)) {
  392. /* first, remove the file handle for this index, if we have it open */
  393. PR_Lock(inst->inst_handle_list_mutex);
  394. if (a->ai_dblayer) {
  395. /* there is a handle */
  396. handle = (dblayer_handle *)a->ai_dblayer;
  397. /* when we successfully called dblayer_get_index_file we bumped up
  398. the reference count of how many threads are using the index. So we
  399. must manually back off the count by one here.... rwagner */
  400. dblayer_release_index_file(be, a, db);
  401. while (slapi_atomic_load_64(&(a->ai_dblayer_count), __ATOMIC_ACQUIRE) > 0) {
  402. /* someone is using this index file */
  403. /* ASSUMPTION: you have already set the INDEX_OFFLINE flag, because
  404. * you intend to mess with this index. therefore no new requests
  405. * for this indexfile should happen, so the dblayer_count should
  406. * NEVER increase.
  407. */
  408. PR_ASSERT(a->ai_indexmask & INDEX_OFFLINE);
  409. PR_Unlock(inst->inst_handle_list_mutex);
  410. DS_Sleep(DBLAYER_CACHE_DELAY);
  411. PR_Lock(inst->inst_handle_list_mutex);
  412. }
  413. rc = dbmdb_dbi_remove(conf, &db);
  414. slapi_ch_free_string(&dbname);
  415. a->ai_dblayer = NULL;
  416. if (rc == 0) {
  417. /* remove handle from handle-list */
  418. if (inst->inst_handle_head == handle) {
  419. inst->inst_handle_head = handle->dblayer_handle_next;
  420. if (inst->inst_handle_tail == handle) {
  421. inst->inst_handle_tail = NULL;
  422. }
  423. } else {
  424. dblayer_handle *hp;
  425. for (hp = inst->inst_handle_head; hp; hp = hp->dblayer_handle_next) {
  426. if (hp->dblayer_handle_next == handle) {
  427. hp->dblayer_handle_next = handle->dblayer_handle_next;
  428. if (inst->inst_handle_tail == handle) {
  429. inst->inst_handle_tail = hp;
  430. }
  431. break;
  432. }
  433. }
  434. }
  435. slapi_ch_free((void **)&handle);
  436. } else {
  437. rc = -1; /* Failed to remove the db instance */
  438. }
  439. } else {
  440. /* no handle to close */
  441. }
  442. PR_Unlock(inst->inst_handle_list_mutex);
  443. }
  444. return rc;
  445. }
  446. /*
  447. * Transaction stuff. The idea is that the caller doesn't need to
  448. * know the transaction mechanism underneath (because the caller is
  449. * typically a few calls up the stack from any MDB_dbistuff).
  450. * Sadly, in slapd there was no handy structure associated with
  451. * an LDAP operation, and passed around everywhere, so we had
  452. * to invent the back_txn structure.
  453. * The lower levels of the back-end look into this structure, and
  454. * take out the MDB_txn they need.
  455. */
  456. int
  457. dbmdb_txn_begin(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock)
  458. {
  459. int return_value = -1;
  460. dbmdb_ctx_t *conf = NULL;
  461. back_txn new_txn = {NULL};
  462. PR_ASSERT(NULL != li);
  463. PR_ASSERT(NULL != li->li_dblayer_private);
  464. /*
  465. * When server is shutting down, some components need to
  466. * flush some data (e.g. replication to write ruv).
  467. * So don't check shutdown signal unless we can't write.
  468. */
  469. if (g_get_shutdown() == SLAPI_SHUTDOWN_DISKFULL) {
  470. return return_value;
  471. }
  472. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  473. if (txn) {
  474. txn->back_txn_txn = NULL;
  475. }
  476. if (1) {
  477. dbi_txn_t *new_txn_back_txn_txn = NULL;
  478. if (use_lock)
  479. slapi_rwlock_rdlock(&conf->dbmdb_env_lock);
  480. if (!parent_txn) {
  481. /* see if we have a stored parent txn */
  482. back_txn *par_txn_txn = dblayer_get_pvt_txn();
  483. if (par_txn_txn) {
  484. parent_txn = par_txn_txn->back_txn_txn;
  485. }
  486. }
  487. return_value = START_TXN(&new_txn_back_txn_txn, parent_txn, 0);
  488. return_value = dbmdb_map_error(__FUNCTION__, return_value);
  489. if (0 != return_value) {
  490. if (use_lock)
  491. slapi_rwlock_unlock(&conf->dbmdb_env_lock);
  492. } else {
  493. new_txn.back_txn_txn = new_txn_back_txn_txn;
  494. /* this txn is now our current transaction for current operations
  495. and new parent for any nested transactions created */
  496. dblayer_push_pvt_txn(&new_txn);
  497. if (txn) {
  498. txn->back_txn_txn = new_txn.back_txn_txn;
  499. }
  500. }
  501. } else {
  502. return_value = 0;
  503. }
  504. if (0 != return_value) {
  505. slapi_log_err(SLAPI_LOG_CRIT,
  506. "dblayer_txn_begin_ext", "Serious Error---Failed in dblayer_txn_begin, err=%d (%s)\n",
  507. return_value, dblayer_strerror(return_value));
  508. }
  509. return return_value;
  510. }
  511. int
  512. dbmdb_txn_commit(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
  513. {
  514. int return_value = -1;
  515. dbmdb_ctx_t *conf = NULL;
  516. dblayer_private *priv = NULL;
  517. dbi_txn_t *db_txn = NULL;
  518. back_txn *cur_txn = NULL;
  519. PR_ASSERT(NULL != li);
  520. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  521. priv = li->li_dblayer_private;
  522. PR_ASSERT(NULL != priv);
  523. /* use the transaction we are given - if none, see if there
  524. is a transaction in progress */
  525. if (txn) {
  526. db_txn = txn->back_txn_txn;
  527. }
  528. cur_txn = dblayer_get_pvt_txn();
  529. if (!db_txn) {
  530. if (cur_txn) {
  531. db_txn = cur_txn->back_txn_txn;
  532. }
  533. }
  534. if (NULL != db_txn && conf->env) {
  535. /* if we were given a transaction, and it is the same as the
  536. current transaction in progress, pop it off the stack
  537. or, if no transaction was given, we must be using the
  538. current one - must pop it */
  539. if (!txn || (cur_txn && (cur_txn->back_txn_txn == db_txn))) {
  540. dblayer_pop_pvt_txn();
  541. }
  542. return_value = END_TXN(&db_txn, 0);
  543. return_value = dbmdb_map_error(__FUNCTION__, return_value);
  544. if (txn) {
  545. /* this handle is no longer value - set it to NULL */
  546. txn->back_txn_txn = NULL;
  547. }
  548. if (use_lock)
  549. slapi_rwlock_unlock(&conf->dbmdb_env_lock);
  550. } else {
  551. return_value = 0;
  552. }
  553. if (0 != return_value) {
  554. slapi_log_err(SLAPI_LOG_CRIT,
  555. "dblayer_txn_commit_ext", "Serious Error---Failed in dblayer_txn_commit, err=%d (%s)\n",
  556. return_value, dblayer_strerror(return_value));
  557. if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
  558. operation_out_of_disk_space();
  559. }
  560. }
  561. return return_value;
  562. }
  563. int
  564. dbmdb_txn_abort(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
  565. {
  566. int return_value = -1;
  567. dbi_txn_t *db_txn = NULL;
  568. back_txn *cur_txn = NULL;
  569. dbmdb_ctx_t *conf = NULL;
  570. PR_ASSERT(NULL != li);
  571. PR_ASSERT(NULL != li->li_dblayer_private);
  572. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  573. /* use the transaction we are given - if none, see if there
  574. is a transaction in progress */
  575. if (txn) {
  576. db_txn = txn->back_txn_txn;
  577. }
  578. cur_txn = dblayer_get_pvt_txn();
  579. if (!db_txn) {
  580. if (cur_txn) {
  581. db_txn = cur_txn->back_txn_txn;
  582. }
  583. }
  584. if (NULL != db_txn && conf->env) {
  585. /* if we were given a transaction, and it is the same as the
  586. current transaction in progress, pop it off the stack
  587. or, if no transaction was given, we must be using the
  588. current one - must pop it */
  589. if (!txn || (cur_txn && (cur_txn->back_txn_txn == db_txn))) {
  590. dblayer_pop_pvt_txn();
  591. }
  592. END_TXN(&db_txn, 1);
  593. return_value = 0;
  594. if (txn) {
  595. /* this handle is no longer value - set it to NULL */
  596. txn->back_txn_txn = NULL;
  597. }
  598. if (use_lock)
  599. slapi_rwlock_unlock(&conf->dbmdb_env_lock);
  600. } else {
  601. return_value = 0;
  602. }
  603. if (0 != return_value) {
  604. slapi_log_err(SLAPI_LOG_CRIT,
  605. "dblayer_txn_abort_ext", "Serious Error---Failed in dblayer_txn_abort, err=%d (%s)\n",
  606. return_value, dblayer_strerror(return_value));
  607. if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
  608. operation_out_of_disk_space();
  609. }
  610. }
  611. return return_value;
  612. }
  613. /* delete the db instances in a specific backend instance --
  614. * this is probably only used for import.
  615. * assumption: dblayer is open, but the instance has been closed.
  616. */
  617. int
  618. dbmdb_delete_instance_dir(backend *be)
  619. {
  620. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  621. int ret = dbmdb_force_checkpoint(li);
  622. if (ret != 0) {
  623. return ret;
  624. } else {
  625. return dbmdb_dbi_rmdir(be);
  626. }
  627. }
  628. /* delete an entire db/ directory, including all instances under it!
  629. * this is used mostly for restores.
  630. * dblayer is assumed to be closed.
  631. */
  632. int
  633. dbmdb_delete_db(struct ldbminfo *li)
  634. {
  635. char path[MAXPATHLEN];
  636. PR_snprintf(path, MAXPATHLEN, "%s/%s", MDB_CONFIG(li)->home, DBMAPFILE);
  637. unlink(path);
  638. PR_snprintf(path, MAXPATHLEN, "%s/lock.mdb", MDB_CONFIG(li)->home);
  639. unlink(path);
  640. PR_snprintf(path, MAXPATHLEN, "%s/INFO.mdb", MDB_CONFIG(li)->home);
  641. unlink(path);
  642. return 0;
  643. }
  644. /*
  645. * Return the current size of the database (in bytes).
  646. */
  647. uint64_t
  648. dbmdb_database_size(struct ldbminfo *li)
  649. {
  650. dbmdb_ctx_t *priv = NULL;
  651. PRFileInfo64 info = {0};
  652. char path[MAXPATHLEN];
  653. PR_ASSERT(NULL != li);
  654. priv = (dbmdb_ctx_t *)li->li_dblayer_config;
  655. PR_ASSERT(NULL != priv);
  656. PR_ASSERT(NULL != priv->home);
  657. PR_snprintf(path, MAXPATHLEN, "%s/%s", priv->home, DBMAPFILE);
  658. PR_GetFileInfo64(path, &info); /* Ignores errors */
  659. return info.size;
  660. }
  661. /* And finally... Tubular Bells.
  662. * Well, no, actually backup and restore...
  663. */
  664. /* Backup works like this:
  665. * the slapd executable is run like for ldif2ldbm and so on.
  666. * this means that the front-end gets the back-end loaded, and then calls
  667. * into the back-end backup entry point. This then gets us down to here.
  668. *
  669. * So, we need to copy the data files to the backup point.
  670. * While we are doing that, we need to make sure that the logfile
  671. * truncator in slapd doesn't delete our files. To do this we need
  672. * some way to signal to it that it should cease its work, or we need
  673. * to do something like start a long-lived transaction so that the
  674. * log files look like they're needed.
  675. *
  676. * When we've copied the data files, we can then copy the log files
  677. * too.
  678. *
  679. * Finally, we tell the log file truncator to go back about its business in peace
  680. *
  681. */
  682. int
  683. dbmdb_copyfile(char *source, char *destination, int overwrite __attribute__((unused)), int mode)
  684. {
  685. #ifdef DB_USE_64LFS
  686. #define OPEN_FUNCTION dbmdb_open_large
  687. #else
  688. #define OPEN_FUNCTION open
  689. #endif
  690. int source_fd = -1;
  691. int dest_fd = -1;
  692. char *buffer = NULL;
  693. int return_value = -1;
  694. int bytes_to_write = 0;
  695. /* malloc the buffer */
  696. buffer = slapi_ch_malloc(64 * 1024);
  697. if (NULL == buffer) {
  698. goto error;
  699. }
  700. /* Open source file */
  701. source_fd = OPEN_FUNCTION(source, O_RDONLY, 0);
  702. if (-1 == source_fd) {
  703. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_copyfile", "Failed to open source file %s by \"%s\"\n",
  704. source, strerror(errno));
  705. goto error;
  706. }
  707. /* Open destination file */
  708. dest_fd = OPEN_FUNCTION(destination, O_CREAT | O_WRONLY, mode);
  709. if (-1 == dest_fd) {
  710. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_copyfile", "Failed to open dest file %s by \"%s\"\n",
  711. destination, strerror(errno));
  712. goto error;
  713. }
  714. slapi_log_err(SLAPI_LOG_INFO,
  715. "dbmdb_copyfile", "Copying %s to %s\n", source, destination);
  716. /* Loop round reading data and writing it */
  717. while (1) {
  718. int i;
  719. char *ptr = NULL;
  720. return_value = read(source_fd, buffer, 64 * 1024);
  721. if (return_value <= 0) {
  722. /* means error or EOF */
  723. if (return_value < 0) {
  724. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_copyfile", "Failed to read by \"%s\": rval = %d\n",
  725. strerror(errno), return_value);
  726. }
  727. break;
  728. }
  729. bytes_to_write = return_value;
  730. ptr = buffer;
  731. #define CPRETRY 4
  732. for (i = 0; i < CPRETRY; i++) { /* retry twice */
  733. return_value = write(dest_fd, ptr, bytes_to_write);
  734. if (return_value == bytes_to_write) {
  735. break;
  736. } else {
  737. /* means error */
  738. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_copyfile", "Failed to write by \"%s\"; real: %d bytes, exp: %d bytes\n",
  739. strerror(errno), return_value, bytes_to_write);
  740. if (return_value > 0) {
  741. bytes_to_write -= return_value;
  742. ptr += return_value;
  743. slapi_log_err(SLAPI_LOG_NOTICE, "dbmdb_copyfile", "Retrying to write %d bytes\n", bytes_to_write);
  744. } else {
  745. break;
  746. }
  747. }
  748. }
  749. if ((CPRETRY == i) || (return_value < 0)) {
  750. return_value = -1;
  751. break;
  752. }
  753. }
  754. error:
  755. if (source_fd != -1) {
  756. close(source_fd);
  757. }
  758. if (dest_fd != -1) {
  759. close(dest_fd);
  760. }
  761. slapi_ch_free((void **)&buffer);
  762. return return_value;
  763. }
  764. /* Destination Directory is an absolute pathname */
  765. int
  766. dbmdb_backup(struct ldbminfo *li, char *dest_dir, Slapi_Task *task)
  767. {
  768. int return_value = LDAP_UNWILLING_TO_PERFORM;
  769. PRDirEntry *direntry = NULL;
  770. PRDir *dirhandle = NULL;
  771. dbmdb_ctx_t *conf;
  772. char *pathname1;
  773. char *pathname2;
  774. const char **pt;
  775. char *home;
  776. PR_ASSERT(NULL != li);
  777. PR_ASSERT(NULL != li->li_dblayer_private);
  778. conf = (dbmdb_ctx_t *)li->li_dblayer_config;
  779. PR_ASSERT(NULL != conf);
  780. home = conf->home;
  781. if ('\0' == *home) {
  782. slapi_log_err(SLAPI_LOG_ERR,
  783. "dblayer_backup", "Missing db home directory info\n");
  784. return return_value;
  785. }
  786. /*
  787. * What are we doing here ?
  788. * check that destinantion is OK
  789. * We want to copy into the backup directory:
  790. * The mdb database
  791. * The info file
  792. */
  793. if (g_get_shutdown() || c_get_shutdown()) {
  794. slapi_log_err(SLAPI_LOG_WARNING, "dblayer_backup", "Server shutting down, backup aborted\n");
  795. return_value = -1;
  796. goto bail;
  797. }
  798. return_value = mkdir_p(dest_dir, 0700);
  799. dirhandle = PR_OpenDir(dest_dir);
  800. if (NULL != dirhandle) {
  801. while ((direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)) && direntry->name) {
  802. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_backup", "Backup directory %s is not empty.\n", dest_dir);
  803. if (task) {
  804. slapi_task_log_notice(task, "dbmdb_backup - Backup directory %s is not empty.\n", dest_dir);
  805. }
  806. PR_CloseDir(dirhandle);
  807. goto error_out;
  808. }
  809. PR_CloseDir(dirhandle);
  810. } else {
  811. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_backup", "Cannot open backup directory %s.\n", dest_dir);
  812. if (task) {
  813. slapi_task_log_notice(task, "dbmdb_backup - Backup directory %s is not empty.\n", dest_dir);
  814. }
  815. goto error_out;
  816. }
  817. /* Copy the mdb database */
  818. return_value = mdb_env_copy(conf->env, dest_dir);
  819. if (return_value) {
  820. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_backup", "Failed to backup mdb database to %s.\n", dest_dir);
  821. if (task) {
  822. slapi_task_log_notice(task, "dbmdb_backup - Failed to backup mdb database to %s.\n", dest_dir);
  823. }
  824. goto error_out;
  825. }
  826. /* now copy the info file */
  827. pathname1 = slapi_ch_smprintf("%s/%s", home, INFOFILE);
  828. pathname2 = slapi_ch_smprintf("%s/%s", dest_dir, INFOFILE);
  829. slapi_log_err(SLAPI_LOG_INFO, "dblayer_backup", "Backing up file d (%s)\n", pathname2);
  830. if (task) {
  831. slapi_task_log_notice(task, "Backing up file (%s)", pathname2);
  832. }
  833. return_value = dbmdb_copyfile(pathname1, pathname2, 0, li->li_mode | 0400);
  834. if (0 > return_value) {
  835. slapi_log_err(SLAPI_LOG_ERR,
  836. "dblayer_backup", "Error in copying version file "
  837. "(%s -> %s): err=%d\n",
  838. pathname1, pathname2, return_value);
  839. if (task) {
  840. slapi_task_log_notice(task,
  841. "Backup: error in copying version file "
  842. "(%s -> %s): err=%d\n",
  843. pathname1, pathname2, return_value);
  844. }
  845. }
  846. slapi_ch_free((void **)&pathname1);
  847. slapi_ch_free((void **)&pathname2);
  848. if (0 == return_value) /* if everything went well, backup the index conf */
  849. return_value = dbmdb_dse_conf_backup(li, dest_dir);
  850. goto bail;
  851. error_out:
  852. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_backup", "Backup to %s aborted.\n", dest_dir);
  853. if (task) {
  854. slapi_task_log_notice(task, "dbmdb_backup - Backup to %s aborted.\n", dest_dir);
  855. }
  856. /* Lets remove the backup */
  857. for (pt=backupfilelists; *pt; pt++) {
  858. pathname2 = slapi_ch_smprintf("%s/%s", dest_dir, *pt);
  859. unlink(pathname2);
  860. slapi_ch_free_string(&pathname2);
  861. }
  862. rmdir(dest_dir);
  863. return_value = LDAP_UNWILLING_TO_PERFORM;
  864. bail:
  865. return return_value;
  866. }
  867. /*
  868. * Restore is pretty easy.
  869. * We delete the current database.
  870. * We then copy all the files over from the backup point.
  871. * We then leave them there for the slapd process to pick up and do the recovery
  872. * (which it will do as it sees no guard file).
  873. */
  874. /* Helper function first */
  875. static int
  876. dbmdb_restore_file(struct ldbminfo *li, Slapi_Task *task, const char *src_dir, const char *filename)
  877. {
  878. char *pathname1 = slapi_ch_smprintf("%s/%s", src_dir, filename);
  879. char *pathname2 = slapi_ch_smprintf("%s/%s", MDB_CONFIG(li)->home, filename);
  880. int return_value = dbmdb_copyfile(pathname1, pathname2, PR_TRUE, li->li_mode);
  881. if (return_value) {
  882. slapi_log_err(SLAPI_LOG_ERR,
  883. "dbmdb_restore", "Failed to copy database map file to %s.\n", pathname2);
  884. if (task) {
  885. slapi_task_log_notice(task, "Restore: Failed to copy database map file to %s.\n", pathname2);
  886. }
  887. slapi_ch_free_string(&pathname1);
  888. slapi_ch_free_string(&pathname2);
  889. return -1;
  890. }
  891. slapi_ch_free_string(&pathname1);
  892. slapi_ch_free_string(&pathname2);
  893. return 0;
  894. }
  895. int
  896. dbmdb_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
  897. {
  898. int return_value = 0;
  899. int tmp_rval;
  900. int dbmode = DBLAYER_RESTORE_NO_RECOVERY_MODE;
  901. struct stat sbuf;
  902. const char **pt;
  903. char *pathname;
  904. PR_ASSERT(NULL != li);
  905. PR_ASSERT(NULL != li->li_dblayer_private);
  906. /* We find out if slapd is startcfg */
  907. /* If it is, we fail */
  908. /* We check on the source staging area, no point in going further if it
  909. * isn't there */
  910. if (stat(src_dir, &sbuf) < 0) {
  911. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_restore", "Backup directory %s does not "
  912. "exist.\n",
  913. src_dir);
  914. if (task) {
  915. slapi_task_log_notice(task, "Restore: backup directory %s does not exist.",
  916. src_dir);
  917. }
  918. return LDAP_UNWILLING_TO_PERFORM;
  919. } else if (!S_ISDIR(sbuf.st_mode)) {
  920. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_restore", "Backup directory %s is not "
  921. "a directory.\n",
  922. src_dir);
  923. if (task) {
  924. slapi_task_log_notice(task, "Restore: backup directory %s is not a directory.",
  925. src_dir);
  926. }
  927. return LDAP_UNWILLING_TO_PERFORM;
  928. }
  929. /* Check that all files are present and not empty */
  930. for (pt=backupfilelists; *pt; pt++) {
  931. pathname = slapi_ch_smprintf("%s/%s", src_dir, *pt);
  932. if (stat(pathname, &sbuf) < 0 || sbuf.st_size == 0) {
  933. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_restore",
  934. "Backup directory %s does not contain a complete backup.\n", src_dir);
  935. if (task) {
  936. slapi_task_log_notice(task,
  937. "Restore: backup directory %s does not contain a complete backup.", src_dir);
  938. }
  939. slapi_ch_free_string(&pathname);
  940. return LDAP_UNWILLING_TO_PERFORM;
  941. }
  942. slapi_ch_free_string(&pathname);
  943. }
  944. /* Check that current backend instance are compatible with backup. */
  945. /* And reset index configuration to the backup one */
  946. tmp_rval = dbmdb_dse_conf_verify(li, src_dir);
  947. if (tmp_rval != 0) {
  948. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_restore", "Backup directory %s is not compatible "
  949. "with current configuration.\n", src_dir);
  950. if (task) {
  951. slapi_task_log_notice(task, "Restore: backup directory %s is not compatible "
  952. "with current configuration.", src_dir);
  953. }
  954. return LDAP_UNWILLING_TO_PERFORM;
  955. }
  956. /* We delete the existing database */
  957. dbmdb_ctx_close(li->li_dblayer_config);
  958. dbmdb_delete_db(li);
  959. /* Copy db and info files */
  960. if (dbmdb_restore_file(li, task, src_dir, DBMAPFILE) ||
  961. dbmdb_restore_file(li, task, src_dir, INFOFILE)) {
  962. return_value = -1;
  963. goto error_out;
  964. }
  965. /* restart the db */
  966. slapi_ch_free(&li->li_dblayer_config); /* mdb_init will recreate it */
  967. mdb_init(li, NULL);
  968. tmp_rval = dbmdb_start(li, dbmode);
  969. if (0 != tmp_rval) {
  970. slapi_log_err(SLAPI_LOG_ERR,
  971. "dbmdb_restore", "Failed to init database\n");
  972. if (task) {
  973. slapi_task_log_notice(task, "dbmdb_restore - Failed to init database");
  974. }
  975. return_value = tmp_rval;
  976. goto error_out;
  977. }
  978. if (0 != tmp_rval)
  979. slapi_log_err(SLAPI_LOG_WARNING, "dbmdb_restore", "Unable to verify the index configuration\n");
  980. if (li->li_flags & SLAPI_TASK_RUNNING_FROM_COMMANDLINE) {
  981. /* command line: close the database down again */
  982. tmp_rval = dblayer_close(li, dbmode);
  983. if (0 != tmp_rval) {
  984. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_restore", "Failed to close database\n");
  985. }
  986. } else {
  987. allinstance_set_busy(li); /* on-line mode */
  988. }
  989. return_value = tmp_rval ? tmp_rval : return_value;
  990. error_out:
  991. return return_value;
  992. }
  993. static char *
  994. dbmdb__import_file_name(ldbm_instance *inst)
  995. {
  996. char *fname = slapi_ch_smprintf("%s/../.import_%s",
  997. inst->inst_li->li_directory,
  998. inst->inst_name);
  999. return fname;
  1000. }
  1001. static char *
  1002. dbmdb_restore_file_name(struct ldbminfo *li)
  1003. {
  1004. char *fname = slapi_ch_smprintf("%s/../.restore", li->li_directory);
  1005. return fname;
  1006. }
  1007. static int
  1008. dbmdb_file_open(char *fname, int flags, int mode, PRFileDesc **prfd)
  1009. {
  1010. int rc = 0;
  1011. *prfd = PR_Open(fname, flags, mode);
  1012. if (NULL == *prfd)
  1013. rc = PR_GetError();
  1014. if (rc && rc != PR_FILE_NOT_FOUND_ERROR) {
  1015. slapi_log_err(SLAPI_LOG_ERR,
  1016. "dbmdb_file_open", "Failed to open file: %s, error: (%d) %s\n",
  1017. fname, rc, slapd_pr_strerror(rc));
  1018. }
  1019. return rc;
  1020. }
  1021. int
  1022. dbmdb_import_file_init(ldbm_instance *inst)
  1023. {
  1024. int rc = -1;
  1025. PRFileDesc *prfd = NULL;
  1026. char *fname = dbmdb__import_file_name(inst);
  1027. rc = dbmdb_file_open(fname, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, inst->inst_li->li_mode, &prfd);
  1028. if (prfd) {
  1029. PR_Close(prfd);
  1030. rc = 0;
  1031. }
  1032. slapi_ch_free_string(&fname);
  1033. return rc;
  1034. }
  1035. int
  1036. dbmdb_restore_file_init(struct ldbminfo *li)
  1037. {
  1038. int rc = -1;
  1039. PRFileDesc *prfd;
  1040. char *fname = dbmdb_restore_file_name(li);
  1041. rc = dbmdb_file_open(fname, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, li->li_mode, &prfd);
  1042. if (prfd) {
  1043. PR_Close(prfd);
  1044. rc = 0;
  1045. }
  1046. slapi_ch_free_string(&fname);
  1047. return rc;
  1048. }
  1049. void
  1050. dbmdb_import_file_update(ldbm_instance *inst)
  1051. {
  1052. PRFileDesc *prfd;
  1053. char *fname = dbmdb__import_file_name(inst);
  1054. dbmdb_file_open(fname, PR_RDWR, inst->inst_li->li_mode, &prfd);
  1055. if (prfd) {
  1056. char *line = slapi_ch_smprintf("import of %s succeeded", inst->inst_dir_name);
  1057. slapi_write_buffer(prfd, line, strlen(line));
  1058. slapi_ch_free_string(&line);
  1059. PR_Close(prfd);
  1060. }
  1061. slapi_ch_free_string(&fname);
  1062. }
  1063. int
  1064. dbmdb_file_check(char *fname, int mode)
  1065. {
  1066. int rc = 0;
  1067. int err;
  1068. PRFileDesc *prfd;
  1069. err = dbmdb_file_open(fname, PR_RDWR, mode, &prfd);
  1070. if (prfd) {
  1071. /* file exists, additional check on size */
  1072. PRFileInfo64 prfinfo;
  1073. rc = 1;
  1074. /* read it */
  1075. err = PR_GetOpenFileInfo64(prfd, &prfinfo);
  1076. if (err == PR_SUCCESS && 0 == prfinfo.size) {
  1077. /* it is empty restore or import has failed */
  1078. slapi_log_err(SLAPI_LOG_ERR,
  1079. "dbmdb_file_check", "Previous import or restore failed, file: %s is empty\n", fname);
  1080. }
  1081. PR_Close(prfd);
  1082. PR_Delete(fname);
  1083. } else {
  1084. if (PR_FILE_NOT_FOUND_ERROR == err) {
  1085. rc = 0;
  1086. } else {
  1087. /* file exists, but we cannot open it */
  1088. rc = 1;
  1089. /* error is already looged try to delete it*/
  1090. PR_Delete(fname);
  1091. }
  1092. }
  1093. return rc;
  1094. }
  1095. int
  1096. dbmdb_import_file_check(ldbm_instance *inst)
  1097. {
  1098. int rc;
  1099. char *fname = dbmdb__import_file_name(inst);
  1100. rc = dbmdb_file_check(fname, inst->inst_li->li_mode);
  1101. slapi_ch_free_string(&fname);
  1102. return rc;
  1103. }
  1104. void
  1105. dbmdb_restore_file_update(struct ldbminfo *li, const char *directory)
  1106. {
  1107. PRFileDesc *prfd;
  1108. char *fname = dbmdb_restore_file_name(li);
  1109. dbmdb_file_open(fname, PR_RDWR, li->li_mode, &prfd);
  1110. slapi_ch_free_string(&fname);
  1111. if (prfd) {
  1112. char *line = slapi_ch_smprintf("restore of %s succeeded", directory);
  1113. slapi_write_buffer(prfd, line, strlen(line));
  1114. slapi_ch_free_string(&line);
  1115. PR_Close(prfd);
  1116. }
  1117. }
  1118. /*
  1119. * delete the index files belonging to the instance
  1120. */
  1121. int
  1122. dbmdb_delete_indices(ldbm_instance *inst)
  1123. {
  1124. int rval = -1;
  1125. struct attrinfo *a = NULL;
  1126. int i;
  1127. if (NULL == inst) {
  1128. slapi_log_err(SLAPI_LOG_ERR,
  1129. "dbmdb_delete_indices", "NULL instance is passed\n");
  1130. return rval;
  1131. }
  1132. rval = 0;
  1133. for (a = (struct attrinfo *)avl_getfirst(inst->inst_attrs), i = 0;
  1134. NULL != a;
  1135. a = (struct attrinfo *)avl_getnext(), i++) {
  1136. rval += dbmdb_rm_db_file(inst->inst_be, a, PR_TRUE, i /* chkpt; 1st time only */);
  1137. }
  1138. return rval;
  1139. }
  1140. void
  1141. dbmdb_set_recovery_required(struct ldbminfo *li)
  1142. {
  1143. /* No recovery with lmdb */
  1144. }
  1145. int
  1146. dbmdb_get_info(Slapi_Backend *be, int cmd, void **info)
  1147. {
  1148. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  1149. dbmdb_ctx_t *ctx;
  1150. int rc = -1;
  1151. if ( !info || !li) {
  1152. return rc;
  1153. }
  1154. ctx = MDB_CONFIG(li);
  1155. switch (cmd) {
  1156. case BACK_INFO_DBENV:
  1157. *(MDB_env **)info = ctx->env;
  1158. rc = 0;
  1159. break;
  1160. case BACK_INFO_DBENV_OPENFLAGS:
  1161. *(int *)info = ctx->readonly ? MDB_RDONLY : 0;
  1162. rc = 0;
  1163. break;
  1164. case BACK_INFO_DB_PAGESIZE:
  1165. case BACK_INFO_INDEXPAGESIZE:
  1166. *(uint32_t *)info = ctx->info.pagesize;
  1167. rc = 0;
  1168. break;
  1169. case BACK_INFO_DIRECTORY:
  1170. if (li) {
  1171. *(char **)info = li->li_directory;
  1172. rc = 0;
  1173. }
  1174. break;
  1175. case BACK_INFO_DBHOME_DIRECTORY:
  1176. case BACK_INFO_DB_DIRECTORY:
  1177. *(char **)info = ctx->home;
  1178. rc = 0;
  1179. break;
  1180. case BACK_INFO_INSTANCE_DIR:
  1181. if (li) {
  1182. ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
  1183. *(char **)info = dblayer_get_full_inst_dir(li, inst, NULL, 0);
  1184. rc = 0;
  1185. }
  1186. break;
  1187. case BACK_INFO_LOG_DIRECTORY: {
  1188. if (li) {
  1189. *(char **)info = NULL;
  1190. rc = 0;
  1191. }
  1192. break;
  1193. }
  1194. case BACK_INFO_IS_ENTRYRDN: {
  1195. *(int *)info = entryrdn_get_switch();
  1196. break;
  1197. }
  1198. case BACK_INFO_INDEX_KEY : {
  1199. rc = get_suffix_key(be, (struct _back_info_index_key *)info);
  1200. break;
  1201. }
  1202. case BACK_INFO_DBENV_CLDB: {
  1203. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  1204. if (inst->inst_changelog) {
  1205. rc = 0;
  1206. } else {
  1207. dbmdb_dbi_t *db;
  1208. rc = dblayer_get_changelog(be, (dbi_db_t **)&db, DBOPEN_CREATE);
  1209. }
  1210. if (rc == 0) {
  1211. *(dbmdb_dbi_t **)info = inst->inst_changelog;
  1212. } else {
  1213. *(dbmdb_dbi_t **)info = NULL;
  1214. }
  1215. break;
  1216. }
  1217. case BACK_INFO_CLDB_FILENAME: {
  1218. *(char **)info = BDB_CL_FILENAME;
  1219. rc = 0;
  1220. break;
  1221. }
  1222. default:
  1223. break;
  1224. }
  1225. return rc;
  1226. }
  1227. int
  1228. dbmdb_set_info(Slapi_Backend *be, int cmd, void **info)
  1229. {
  1230. int rc = -1;
  1231. switch (cmd) {
  1232. case BACK_INFO_INDEX_KEY : {
  1233. rc = set_suffix_key(be, (struct _back_info_index_key *)info);
  1234. break;
  1235. }
  1236. default:
  1237. break;
  1238. }
  1239. return rc;
  1240. }
  1241. int
  1242. dbmdb_back_ctrl(Slapi_Backend *be, int cmd, void *info)
  1243. {
  1244. int rc = -1;
  1245. if (!be || !info) {
  1246. return rc;
  1247. }
  1248. switch (cmd) {
  1249. case BACK_INFO_CRYPT_INIT: {
  1250. back_info_crypt_init *crypt_init = (back_info_crypt_init *)info;
  1251. Slapi_DN configdn;
  1252. slapi_sdn_init(&configdn);
  1253. be_getbasedn(be, &configdn);
  1254. char *crypt_dn = slapi_ch_smprintf("%s,%s",
  1255. crypt_init->dn,
  1256. slapi_sdn_get_dn(&configdn));
  1257. rc = back_crypt_init(crypt_init->be, crypt_dn,
  1258. crypt_init->encryptionAlgorithm,
  1259. &(crypt_init->state_priv));
  1260. break;
  1261. }
  1262. case BACK_INFO_CRYPT_DESTROY: {
  1263. back_info_crypt_destroy *crypt_init = (back_info_crypt_destroy *)info;
  1264. rc = back_crypt_destroy(crypt_init->state_priv);
  1265. break;
  1266. }
  1267. case BACK_INFO_CRYPT_ENCRYPT_VALUE: {
  1268. back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
  1269. rc = back_crypt_encrypt_value(crypt_value->state_priv, crypt_value->in,
  1270. &(crypt_value->out));
  1271. break;
  1272. }
  1273. case BACK_INFO_CRYPT_DECRYPT_VALUE: {
  1274. back_info_crypt_value *crypt_value = (back_info_crypt_value *)info;
  1275. rc = back_crypt_decrypt_value(crypt_value->state_priv, crypt_value->in,
  1276. &(crypt_value->out));
  1277. break;
  1278. }
  1279. case BACK_INFO_DBENV_CLDB_REMOVE: {
  1280. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  1281. ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
  1282. if (li) {
  1283. dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
  1284. if (priv && priv->dblayer_env) {
  1285. char *instancedir;
  1286. dbmdb_dbi_t *dbi = NULL;
  1287. slapi_back_get_info(be, BACK_INFO_INSTANCE_DIR, (void **)&instancedir);
  1288. rc = dbmdb_open_dbi_from_filename(&dbi, be, BDB_CL_FILENAME, NULL, 0);
  1289. if (rc == MDB_NOTFOUND) {
  1290. /* Nothing to do */
  1291. rc = 0;
  1292. } else if (rc == 0) {
  1293. rc = dbmdb_dbi_remove(MDB_CONFIG(li), (dbi_db_t**)&dbi);
  1294. }
  1295. inst->inst_changelog = NULL;
  1296. slapi_ch_free_string(&instancedir);
  1297. }
  1298. }
  1299. break;
  1300. }
  1301. case BACK_INFO_DBENV_CLDB_UPGRADE: {
  1302. break;
  1303. }
  1304. case BACK_INFO_CLDB_GET_CONFIG: {
  1305. /* get a config entry relative to the
  1306. * backend config entry
  1307. * Caller must free the returned entry (config->ce)
  1308. * If it fails config->ce is left unchanged
  1309. */
  1310. back_info_config_entry *config = (back_info_config_entry *)info;
  1311. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  1312. Slapi_DN configdn;
  1313. slapi_sdn_init(&configdn);
  1314. be_getbasedn(be, &configdn);
  1315. char *config_dn = slapi_ch_smprintf("%s,%s",
  1316. config->dn,
  1317. slapi_sdn_get_dn(&configdn));
  1318. Slapi_PBlock *search_pb = slapi_pblock_new();
  1319. slapi_search_internal_set_pb(search_pb, config_dn, LDAP_SCOPE_BASE, "objectclass=*",
  1320. NULL, 0, NULL, NULL, li->li_identity, 0);
  1321. slapi_search_internal_pb(search_pb);
  1322. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1323. if (LDAP_SUCCESS == rc ) {
  1324. Slapi_Entry **entries;
  1325. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  1326. if (entries && entries[0]) {
  1327. config->ce = slapi_entry_dup(entries[0]);
  1328. } else {
  1329. rc = -1;
  1330. }
  1331. }
  1332. slapi_free_search_results_internal(search_pb);
  1333. slapi_pblock_destroy(search_pb);
  1334. slapi_ch_free_string(&config_dn);
  1335. break;
  1336. }
  1337. case BACK_INFO_CLDB_SET_CONFIG: {
  1338. /* This control option allows a plugin to set a backend configuration
  1339. * entry without knowing the location of the backend config.
  1340. * It passes an entry with a relative dn and this dn is expanded by the
  1341. * backend config dn.
  1342. */
  1343. Slapi_DN fulldn;
  1344. Slapi_DN configdn;
  1345. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  1346. Slapi_Entry *config_entry = (Slapi_Entry *)info;
  1347. slapi_sdn_init(&configdn);
  1348. be_getbasedn(be, &configdn);
  1349. char *newdn = slapi_ch_smprintf("%s,%s",
  1350. slapi_entry_get_dn_const(config_entry),
  1351. slapi_sdn_get_dn(&configdn));
  1352. slapi_sdn_init(&fulldn);
  1353. slapi_sdn_init_dn_byref(&fulldn, newdn);
  1354. slapi_entry_set_sdn(config_entry, &fulldn);
  1355. slapi_ch_free_string(&newdn);
  1356. Slapi_PBlock *pb = slapi_pblock_new();
  1357. slapi_pblock_init(pb);
  1358. slapi_add_entry_internal_set_pb(pb, config_entry, NULL,
  1359. li->li_identity, 0);
  1360. slapi_add_internal_pb(pb);
  1361. slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  1362. slapi_pblock_destroy(pb);
  1363. break;
  1364. }
  1365. default:
  1366. break;
  1367. }
  1368. return rc;
  1369. }
  1370. dbi_error_t dbmdb_map_error(const char *funcname, int err)
  1371. {
  1372. char *msg = NULL;
  1373. switch (err) {
  1374. case 0:
  1375. return DBI_RC_SUCCESS;
  1376. case MDB_KEYEXIST:
  1377. return DBI_RC_KEYEXIST;
  1378. case MDB_NOTFOUND:
  1379. return DBI_RC_NOTFOUND;
  1380. default:
  1381. msg = mdb_strerror(err);
  1382. if (!msg) {
  1383. msg = "";
  1384. }
  1385. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_map_error",
  1386. "%s failed with db error %d : %s\n", funcname, err, msg);
  1387. log_stack(SLAPI_LOG_ERR);
  1388. return DBI_RC_OTHER;
  1389. }
  1390. }
  1391. /* Conversion a dbi_val_t* into a MDB_val* */
  1392. void dbmdb_dbival2dbt(dbi_val_t *dbi, MDB_val *dbt, PRBool isresponse)
  1393. {
  1394. /*
  1395. * isresponse is true means that dbmdb_dbt2dbival(dbt, dbi, PR_FALSE)
  1396. * is called a few lines before dbmdb_dbival2dbt call
  1397. * This means that if data pointer differs then the buffer has been
  1398. * re alloced ==> should beware not to free it twice
  1399. */
  1400. if (!dbi || !dbt) {
  1401. return;
  1402. }
  1403. dbt->mv_data = dbi->data;
  1404. dbt->mv_size = dbi->size;
  1405. }
  1406. /* Conversion a MDB_val* into a dbi_val_t* */
  1407. int dbmdb_dbt2dbival(MDB_val *dbt, dbi_val_t *dbi, PRBool isresponse, int rc)
  1408. {
  1409. /*
  1410. * isresponse is true means that dbmdb_dbival2dbt(dbt, dbi, PR_FALSE)
  1411. * is called a few lines before dbmdb_dbt2dbival call
  1412. * This means that if data pointer differs then the buffer has been
  1413. * re alloced ==> should beware not to free it twice
  1414. */
  1415. if (!dbi || !dbt || rc) {
  1416. return rc;
  1417. }
  1418. if (dbi->data == dbt->mv_data) {
  1419. /* Value has not changed ==> only update the size */
  1420. dbi->size = dbt->mv_size;
  1421. return rc;
  1422. }
  1423. if (dbi->flags & DBI_VF_READONLY) {
  1424. /* trying to modify read only data */
  1425. return DBI_RC_INVALID;
  1426. }
  1427. if (!isresponse) {
  1428. dbi->flags = DBI_VF_READONLY;
  1429. dbi->data = dbt->mv_data;
  1430. dbi->size = dbt->mv_size;
  1431. return rc;
  1432. }
  1433. if (dbt->mv_size == 0) {
  1434. dbi->size = 0;
  1435. return rc;
  1436. }
  1437. if (dbt->mv_size > dbi->ulen || dbi->data == NULL) {
  1438. if (dbi->flags & DBI_VF_DONTGROW) {
  1439. return DBI_RC_BUFFER_SMALL;
  1440. }
  1441. if (dbi->flags & DBI_VF_PROTECTED) {
  1442. /* make sure not to free the old buffer */
  1443. dbi->data = NULL;
  1444. dbi->flags &= ~DBI_VF_PROTECTED;
  1445. }
  1446. /* Lets realloc the buffer */
  1447. dbi->ulen = dbi->size = dbt->mv_size;
  1448. dbi->data = slapi_ch_realloc(dbi->data, dbi->size);
  1449. }
  1450. dbi->size = dbt->mv_size;
  1451. memcpy(dbi->data, dbt->mv_data, dbt->mv_size);
  1452. return rc;
  1453. }
  1454. /**********************/
  1455. /* dbimpl.c callbacks */
  1456. /**********************/
  1457. char *dbmdb_public_get_db_filename(dbi_db_t *db)
  1458. {
  1459. dbmdb_dbi_t *dbmdb_db = (dbmdb_dbi_t*)db;
  1460. /* We may perhaps have to remove the backend name ... */
  1461. return (char*)(dbmdb_db->dbname);
  1462. }
  1463. int dbmdb_public_bulk_free(dbi_bulk_t *bulkdata)
  1464. {
  1465. if ((bulkdata->v.flags & DBI_VF_BULK_RECORD) && bulkdata->v.size == 1) {
  1466. slapi_ch_free(&((MDB_val *)(bulkdata->v.data))->mv_data);
  1467. bulkdata->v.size = 0;
  1468. }
  1469. /* No specific action required for mdb handling */
  1470. return DBI_RC_SUCCESS;
  1471. }
  1472. int dbmdb_public_bulk_nextdata(dbi_bulk_t *bulkdata, dbi_val_t *data)
  1473. {
  1474. dbmdb_bulkdata_t *dbmdb_data = bulkdata->v.data;
  1475. int *idx = (int*) (&bulkdata->it);
  1476. char *v = dbmdb_data->data.mv_data;
  1477. int rc = 0;
  1478. PR_ASSERT(bulkdata->v.flags & DBI_VF_BULK_DATA);
  1479. if (dbmdb_data->use_multiple) {
  1480. PR_ASSERT(dbmdb_data->data_size);
  1481. if (dbmdb_data->data0.mv_data) {
  1482. dblayer_value_set_buffer(bulkdata->be, data, dbmdb_data->data0.mv_data, dbmdb_data->data_size);
  1483. dbmdb_data->data0.mv_data = NULL;
  1484. } else {
  1485. if (*idx >= dbmdb_data->data.mv_size / dbmdb_data->data_size) {
  1486. return DBI_RC_NOTFOUND;
  1487. }
  1488. v += dbmdb_data->data_size * (*idx)++;
  1489. dblayer_value_set_buffer(bulkdata->be, data, v, dbmdb_data->data_size);
  1490. }
  1491. } else {
  1492. if (!dbmdb_data->op || (*idx)++ >= dbmdb_data->maxrecords) {
  1493. return DBI_RC_NOTFOUND;
  1494. }
  1495. dblayer_value_set_buffer(bulkdata->be, data, v, dbmdb_data->data.mv_size);
  1496. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, &dbmdb_data->data, dbmdb_data->op);
  1497. }
  1498. rc = dbmdb_map_error(__FUNCTION__, rc);
  1499. return rc;
  1500. }
  1501. int dbmdb_public_bulk_nextrecord(dbi_bulk_t *bulkdata, dbi_val_t *key, dbi_val_t *data)
  1502. {
  1503. MDB_val *vals = bulkdata->v.data;
  1504. MDB_val *endvals = &vals[bulkdata->v.size];
  1505. MDB_val *val = NULL;
  1506. int *idx = (int*) (&bulkdata->it);
  1507. PR_ASSERT(bulkdata->v.flags & DBI_VF_BULK_RECORD);
  1508. if (&vals[*idx] >= endvals) {
  1509. return DBI_RC_NOTFOUND;
  1510. }
  1511. val = &vals[*idx];
  1512. dblayer_value_set_buffer(bulkdata->be, key, val->mv_data, val->mv_size);
  1513. val = &vals[*idx+1];
  1514. dblayer_value_set_buffer(bulkdata->be, data, val->mv_data, val->mv_size);
  1515. (*idx) += 2;
  1516. return 0;
  1517. }
  1518. int dbmdb_public_bulk_init(dbi_bulk_t *bulkdata)
  1519. {
  1520. /* No specific action required for mdb handling */
  1521. return DBI_RC_SUCCESS;
  1522. }
  1523. int dbmdb_public_bulk_start(dbi_bulk_t *bulkdata)
  1524. {
  1525. bulkdata->it = (void*) 0;
  1526. return DBI_RC_SUCCESS;
  1527. }
  1528. int dbmdb_fill_bulkop_records(dbi_cursor_t *cursor, dbi_op_t op, dbi_val_t *key, dbi_bulk_t *bulkdata)
  1529. {
  1530. #define BRVAL(dpl) &((MDB_val *)(bulkdata->v.data))[dpl]
  1531. char *endheap = &((char*)(bulkdata->v.data))[bulkdata->v.ulen];
  1532. MDB_cursor *mcursor = (MDB_cursor*)cursor->cur;
  1533. MDB_val *mdata = NULL;
  1534. MDB_val *mkey = NULL;
  1535. int mop = 0;
  1536. int rc = 0;
  1537. /*
  1538. * bulkdata->v format is:
  1539. * ulen : max size of buffer
  1540. * size : 2 * number of records
  1541. * data : MDB_val[size] key_data_pairs / Empty / Heap
  1542. */
  1543. dbmdb_public_bulk_free(bulkdata);
  1544. bulkdata->v.size = 0;
  1545. switch (op)
  1546. {
  1547. case DBI_OP_MOVE_TO_FIRST:
  1548. mop = MDB_FIRST;
  1549. break;
  1550. case DBI_OP_MOVE_TO_KEY:
  1551. mop = MDB_SET;
  1552. break;
  1553. case DBI_OP_NEXT_KEY:
  1554. mop = MDB_NEXT_NODUP;
  1555. break;
  1556. case DBI_OP_NEXT:
  1557. mop = MDB_NEXT;
  1558. break;
  1559. case DBI_OP_NEXT_DATA:
  1560. mop = MDB_NEXT_DUP;
  1561. break;
  1562. default:
  1563. /* Unknown bulk operation */
  1564. PR_ASSERT(op != op);
  1565. break;
  1566. }
  1567. if (!mop) {
  1568. return DBI_RC_UNSUPPORTED;
  1569. }
  1570. while (!rc) {
  1571. char *keyinheap;
  1572. char *datainheap;
  1573. if ((char*)BRVAL(bulkdata->v.size+2) >= endheap) {
  1574. break;
  1575. }
  1576. mkey = BRVAL(bulkdata->v.size);
  1577. mdata = BRVAL(bulkdata->v.size+1);
  1578. mkey->mv_data = mdata->mv_data = NULL;
  1579. mkey->mv_size = mdata->mv_size = 0;
  1580. if (bulkdata->v.size == 0) {
  1581. dbmdb_dbival2dbt(key, mkey, PR_FALSE);
  1582. }
  1583. rc = MDB_CURSOR_GET(mcursor, mkey, mdata, mop);
  1584. if (rc) {
  1585. if ((rc == MDB_NOTFOUND) && bulkdata->v.size) {
  1586. rc = 0;
  1587. }
  1588. rc = dbmdb_map_error(__FUNCTION__, rc);
  1589. break;
  1590. }
  1591. keyinheap = endheap - mkey->mv_size;
  1592. datainheap = keyinheap - mdata->mv_size;
  1593. endheap = datainheap;
  1594. if ((char*)BRVAL(bulkdata->v.size+2) >= datainheap) {
  1595. /* Buffer is too small to store this value */
  1596. if (bulkdata->v.size) {
  1597. MDB_CURSOR_GET(mcursor, mkey, mdata, MDB_PREV);
  1598. break;
  1599. }
  1600. bulkdata->v.size = -1;
  1601. keyinheap = slapi_ch_malloc(mkey->mv_size + mdata->mv_size);
  1602. datainheap = keyinheap + mkey->mv_size;
  1603. }
  1604. mop = MDB_NEXT;
  1605. bulkdata->v.size += 2;
  1606. memcpy(keyinheap, mkey->mv_data, mkey->mv_size);
  1607. memcpy(datainheap, mdata->mv_data, mdata->mv_size);
  1608. mkey->mv_data = keyinheap;
  1609. mdata->mv_data = datainheap;
  1610. if (bulkdata->v.size == 1) {
  1611. break;
  1612. }
  1613. }
  1614. /* Copy last key back to key */
  1615. if (rc == 0) {
  1616. rc = dbmdb_dbt2dbival(mkey, key, PR_TRUE, rc);
  1617. }
  1618. return rc;
  1619. }
  1620. int dbmdb_public_cursor_bulkop(dbi_cursor_t *cursor, dbi_op_t op, dbi_val_t *key, dbi_bulk_t *bulkdata)
  1621. {
  1622. dbmdb_bulkdata_t *dbmdb_data = bulkdata->v.data;
  1623. MDB_cursor *dbmdb_cur = (MDB_cursor*)cursor->cur;
  1624. MDB_val *mval;
  1625. int rc = 0;
  1626. if (!(cursor && cursor->cur))
  1627. return DBI_RC_INVALID;
  1628. if (bulkdata->v.flags & DBI_VF_BULK_RECORD) {
  1629. return dbmdb_fill_bulkop_records(cursor, op, key, bulkdata);
  1630. }
  1631. bulkdata->v.size = sizeof *dbmdb_data;
  1632. dbmdb_data->cursor = (MDB_cursor*)cursor->cur;
  1633. dbmdb_dbival2dbt(key, &dbmdb_data->key, PR_FALSE);
  1634. mdb_dbi_flags(mdb_cursor_txn(dbmdb_cur), mdb_cursor_dbi(dbmdb_cur), &dbmdb_data->dbi_flags);
  1635. dbmdb_data->use_multiple = (dbmdb_data->dbi_flags & MDB_DUPFIXED);
  1636. PR_ASSERT(dbmdb_data->dbi_flags & MDB_DUPSORT);
  1637. dbmdb_data->maxrecords = BULKOP_MAX_RECORDS;
  1638. dbmdb_data->data.mv_data = NULL;
  1639. dbmdb_data->data.mv_size = 0;
  1640. dbmdb_data->op = 0;
  1641. mval = &dbmdb_data->data;
  1642. /* if dbmdb_data->use_multiple:
  1643. * WARNING lmdb documentation about GET_MULTIPLE is wrong:
  1644. * The data is not a MBD_val[2] array as documented but a single MDB_val and the size is the size of all
  1645. * returned items.
  1646. * else:
  1647. * retrieve the first item in bulkdata->key and bulkdata->data and prepare to retieve next item in
  1648. * dbmdb_public_bulk_nextrecord or dbmdb_public_bulk_nextdata
  1649. */
  1650. switch (op)
  1651. {
  1652. case DBI_OP_MOVE_TO_FIRST:
  1653. /* Returns dups of first entries */
  1654. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_FIRST);
  1655. if (rc == 0) {
  1656. dbmdb_data->op = MDB_NEXT_DUP;
  1657. if (dbmdb_data->use_multiple) {
  1658. dbmdb_data->data0 = *mval;
  1659. dbmdb_data->data_size = mval->mv_size;
  1660. memset(mval, 0, sizeof dbmdb_data->data);
  1661. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_GET_MULTIPLE);
  1662. }
  1663. }
  1664. break;
  1665. case DBI_OP_MOVE_TO_KEY:
  1666. /* Move customer to the specified key and returns dups */
  1667. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_SET);
  1668. if (rc == 0) {
  1669. dbmdb_data->op = (bulkdata->v.flags & DBI_VF_BULK_RECORD) ? MDB_NEXT : MDB_NEXT_DUP;
  1670. if (dbmdb_data->use_multiple) {
  1671. dbmdb_data->data0 = *mval;
  1672. dbmdb_data->data_size = mval->mv_size;
  1673. memset(mval, 0, sizeof dbmdb_data->data);
  1674. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_GET_MULTIPLE);
  1675. }
  1676. }
  1677. break;
  1678. case DBI_OP_NEXT_KEY:
  1679. if (dbmdb_data->use_multiple) {
  1680. memset(&dbmdb_data->data0, 0, sizeof dbmdb_data->data0);
  1681. memset(mval, 0, sizeof dbmdb_data->data);
  1682. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_NEXT_MULTIPLE);
  1683. } else {
  1684. rc = MDB_CURSOR_GET(dbmdb_data->cursor, &dbmdb_data->key, mval, MDB_NEXT_NODUP);
  1685. if (rc == 0) {
  1686. dbmdb_data->op = MDB_NEXT_DUP;
  1687. }
  1688. }
  1689. break;
  1690. case DBI_OP_NEXT:
  1691. /* Move cursor to next position and returns dups and/or nodups */
  1692. PR_ASSERT(bulkdata->v.flags & DBI_VF_BULK_RECORD);
  1693. rc = DBI_RC_UNSUPPORTED;
  1694. break;
  1695. case DBI_OP_NEXT_DATA:
  1696. /* Return next blocks of dups */
  1697. /* with lmdb all dups are returned by the multiple operation
  1698. * so there is no need to iterate on next dups
  1699. */
  1700. if (!dbmdb_data->use_multiple && mval->mv_data) {
  1701. /* There are still some data to work on */
  1702. dbmdb_data->op = MDB_NEXT_DUP;
  1703. rc = 0;
  1704. } else if (bulkdata->v.flags & DBI_VF_BULK_RECORD) {
  1705. rc = dbmdb_fill_bulkop_records(cursor, DBI_OP_NEXT, key, bulkdata);
  1706. } else {
  1707. /* When usign multiple there is always a single bloc of dups */
  1708. rc = MDB_NOTFOUND;
  1709. }
  1710. break;
  1711. default:
  1712. /* Unknown bulk operation */
  1713. PR_ASSERT(op != op);
  1714. rc = DBI_RC_UNSUPPORTED;
  1715. break;
  1716. }
  1717. rc = dbmdb_map_error(__FUNCTION__, rc);
  1718. rc = dbmdb_dbt2dbival(&dbmdb_data->key, key, PR_TRUE, rc);
  1719. return rc;
  1720. }
  1721. void dbmdb_generate_recno_cache_key_by_data(MDB_val *cache_key, MDB_val *key, MDB_val *data)
  1722. {
  1723. char *ptdata;
  1724. cache_key->mv_size = 1+key->mv_size+data->mv_size + sizeof (key->mv_size);
  1725. ptdata = cache_key->mv_data = slapi_ch_malloc(cache_key->mv_size);
  1726. ptdata[0] = 'D';
  1727. memcpy(&ptdata[1], key->mv_data, key->mv_size);
  1728. memcpy(&ptdata[1+key->mv_size], data->mv_data, data->mv_size);
  1729. memcpy(&ptdata[1+key->mv_size+data->mv_size], &key->mv_size, sizeof (key->mv_size));
  1730. }
  1731. void dbmdb_generate_recno_cache_key_by_recno(MDB_val *cache_key, dbi_recno_t recno)
  1732. {
  1733. #define RECNO_KEY_SIZE 12
  1734. cache_key->mv_size = RECNO_KEY_SIZE - 1;
  1735. cache_key->mv_data = slapi_ch_malloc(RECNO_KEY_SIZE);
  1736. snprintf(cache_key->mv_data, RECNO_KEY_SIZE, "R%010u", recno);
  1737. }
  1738. int dbmdb_begin_recno_cache_txn(dbmdb_recno_cache_ctx_t *rcctx, dbmdb_txn_ctx_t *txn_ctx, MDB_dbi dbi)
  1739. {
  1740. int rc = 0;
  1741. txn_ctx->env = rcctx->env;
  1742. txn_ctx->cursor = NULL;
  1743. txn_ctx->flags = 0;
  1744. switch (rcctx->mode) {
  1745. default:
  1746. return EINVAL;
  1747. case RCMODE_USE_CURSOR_TXN:
  1748. txn_ctx->txn = rcctx->cursortxn;
  1749. txn_ctx->flags |= DBMDB_TXNCTX_KEEP_TXN;
  1750. break;
  1751. case RCMODE_USE_SUBTXN:
  1752. rc = TXN_BEGIN(rcctx->env, rcctx->cursortxn, 0, &txn_ctx->txn);
  1753. break;
  1754. case RCMODE_USE_NEW_THREAD:
  1755. rc = TXN_BEGIN(rcctx->env, NULL, 0, &txn_ctx->txn);
  1756. break;
  1757. }
  1758. if (dbi>0) {
  1759. if (rc == 0) {
  1760. rc = MDB_CURSOR_OPEN(txn_ctx->txn, dbi, &txn_ctx->cursor);
  1761. }
  1762. }
  1763. return rc;
  1764. }
  1765. int dbmdb_end_recno_cache_txn(dbmdb_txn_ctx_t *txn_ctx, int abort)
  1766. {
  1767. int rc = 0;
  1768. if (txn_ctx->cursor) {
  1769. MDB_CURSOR_CLOSE(txn_ctx->cursor);
  1770. txn_ctx->cursor = NULL;
  1771. }
  1772. if (txn_ctx->txn && !(txn_ctx->flags & DBMDB_TXNCTX_KEEP_TXN)) {
  1773. if (abort || !(txn_ctx->flags & DBMDB_TXNCTX_NEED_COMMIT)) {
  1774. TXN_ABORT(txn_ctx->txn);
  1775. rc = abort;
  1776. } else {
  1777. rc = TXN_COMMIT(txn_ctx->txn);
  1778. }
  1779. txn_ctx->txn = NULL;
  1780. }
  1781. return rc;
  1782. }
  1783. static dbmdb_recno_cache_elmt_t *
  1784. new_rce(int recno, MDB_val *key, MDB_val *data)
  1785. {
  1786. int len = sizeof(dbmdb_recno_cache_elmt_t) + data->mv_size + key->mv_size;
  1787. dbmdb_recno_cache_elmt_t *rce = (dbmdb_recno_cache_elmt_t*) slapi_ch_malloc(len);
  1788. #ifdef DBMDB_DEBUG
  1789. char datastr[50];
  1790. char keystr[50];
  1791. #endif
  1792. rce->recno = recno;
  1793. rce->len = len;
  1794. rce->data.mv_size = data->mv_size;
  1795. rce->key.mv_size = key->mv_size;
  1796. rce->key.mv_data = &rce[1];
  1797. rce->data.mv_data = ((char*)&rce[1]) + rce->key.mv_size;
  1798. memcpy(rce->data.mv_data, data->mv_data, data->mv_size);
  1799. memcpy(rce->key.mv_data, key->mv_data, key->mv_size);
  1800. #ifdef DBMDB_DEBUG
  1801. dbgval2str(keystr, sizeof keystr, &rce->key);
  1802. dbgval2str(datastr, sizeof datastr, &rce->data);
  1803. dbg_log(__FILE__,__LINE__,__FUNCTION__, -1, "Found recno=%d key: %s data: %s", recno, keystr, datastr);
  1804. #endif
  1805. return rce;
  1806. }
  1807. dbmdb_recno_cache_elmt_t *
  1808. dup_rce(dbmdb_recno_cache_elmt_t *rce)
  1809. {
  1810. MDB_val key, data;
  1811. key.mv_size = rce->key.mv_size;
  1812. key.mv_data = &rce[1];
  1813. data.mv_size = rce->data.mv_size;
  1814. data.mv_data = ((char*)&rce[1]) + key.mv_size;
  1815. return new_rce(rce->recno, &key, &data);
  1816. }
  1817. /* Search in the cache the greatest entry smaller or equal to the searched key */
  1818. int dbmdb_recno_cache_search(dbmdb_recno_cache_ctx_t *rcctx)
  1819. {
  1820. dbmdb_txn_ctx_t txn_ctx = {0};
  1821. int rc = 0;
  1822. #define VD(val) ((char*)((val).mv_data))
  1823. /* Search for GREATER OR EQUAL record */
  1824. rcctx->key = rcctx->cache_key;
  1825. rcctx->rce = NULL;
  1826. rc = dbmdb_begin_recno_cache_txn(rcctx, &txn_ctx, rcctx->rcdbi->dbi);
  1827. if (!rc) {
  1828. rc = MDB_CURSOR_GET(txn_ctx.cursor, &rcctx->key, &rcctx->data, MDB_SET_RANGE);
  1829. }
  1830. rcctx->rce = NULL;
  1831. if (rc == 0 && VD(rcctx->cache_key)[0] == VD(rcctx->key)[0] &&
  1832. dbmdb_cmp_vals(&rcctx->cache_key, &rcctx->key) == 0) {
  1833. /* Found directly searched entry */
  1834. rcctx->rce = dup_rce(rcctx->data.mv_data);
  1835. } else {
  1836. if (rc == MDB_NOTFOUND) {
  1837. rc = MDB_CURSOR_GET(txn_ctx.cursor, &rcctx->key, &rcctx->data, MDB_LAST);
  1838. } else if (rc == 0) {
  1839. rc = MDB_CURSOR_GET(txn_ctx.cursor, &rcctx->key, &rcctx->data, MDB_PREV);
  1840. }
  1841. if (rc == 0 && VD(rcctx->cache_key)[0] == VD(rcctx->key)[0]) {
  1842. rcctx->rce = dup_rce(rcctx->data.mv_data);
  1843. }
  1844. }
  1845. rc = dbmdb_end_recno_cache_txn(&txn_ctx, rc);
  1846. return rc;
  1847. }
  1848. /* create or recreate the recno cache */
  1849. void *dbmdb_recno_cache_build(void *arg)
  1850. {
  1851. dbmdb_recno_cache_ctx_t *rcctx = arg;
  1852. dbmdb_recno_cache_elmt_t *rce = NULL;
  1853. dbmdb_txn_ctx_t txn_ctx = {0};
  1854. dbi_recno_t recno = 1;
  1855. MDB_val rcdata = {0};
  1856. MDB_val rckey = {0};
  1857. MDB_stat stat = {0};
  1858. MDB_val data = {0};
  1859. MDB_val key = {0};
  1860. int len = 0;
  1861. int rc = 0;
  1862. /* Open/creat cache dbi */
  1863. rc = dbmdb_open_dbi_from_filename(&rcctx->rcdbi, rcctx->cursor->be, rcctx->rcdbname, NULL, MDB_CREATE);
  1864. slapi_ch_free_string(&rcctx->rcdbname);
  1865. /* Clear the cache if it is not already empty */
  1866. if (rc == 0) {
  1867. rc = dbmdb_begin_recno_cache_txn(rcctx, &txn_ctx, rcctx->dbi->dbi);
  1868. }
  1869. if (rc == 0) {
  1870. key.mv_data = "OK";
  1871. key.mv_size = 2;
  1872. rc = MDB_GET(txn_ctx.txn, rcctx->rcdbi->dbi, &key, &data);
  1873. if (rc == 0) {
  1874. /* Cache is already uptodate ==> nothing to build. */
  1875. goto cache_built;
  1876. }
  1877. /* Lets clear the cache if it is not already empty */
  1878. rc = mdb_stat(txn_ctx.txn, rcctx->rcdbi->dbi, &stat);
  1879. if (stat.ms_entries > 0) {
  1880. rc = MDB_DROP(txn_ctx.txn, rcctx->rcdbi->dbi, 0);
  1881. txn_ctx.flags |= DBMDB_TXNCTX_NEED_COMMIT;
  1882. }
  1883. }
  1884. while (rc == 0) {
  1885. slapi_log_err(SLAPI_LOG_INFO, "dbmdb_recno_cache_build", "recno=%d\n", recno);
  1886. if (recno % RECNO_CACHE_INTERVAL != 1) {
  1887. recno++;
  1888. rc = MDB_CURSOR_GET(txn_ctx.cursor, &key, &data, MDB_NEXT);
  1889. continue;
  1890. }
  1891. /* close the txn from time to time to avoid locking all dbi page */
  1892. rc = dbmdb_end_recno_cache_txn(&txn_ctx, 0);
  1893. rc |= dbmdb_begin_recno_cache_txn(rcctx, &txn_ctx, rcctx->dbi->dbi);
  1894. if (rc) {
  1895. break;
  1896. }
  1897. /* Reset to new cursor to the old position */
  1898. if (recno == 1) {
  1899. rc = MDB_CURSOR_GET(txn_ctx.cursor, &key, &data, MDB_FIRST);
  1900. } else {
  1901. rc = MDB_CURSOR_GET(txn_ctx.cursor, &key, &data, MDB_SET);
  1902. if (rc == MDB_NOTFOUND) {
  1903. rc = MDB_CURSOR_GET(txn_ctx.cursor, &key, &data, MDB_SET_RANGE);
  1904. }
  1905. }
  1906. if (rc) {
  1907. break;
  1908. }
  1909. /* Prepare the cache data */
  1910. len = sizeof(*rce) + data.mv_size + key.mv_size;
  1911. rce = (dbmdb_recno_cache_elmt_t*)slapi_ch_malloc(len);
  1912. rce->len = len;
  1913. rce->recno = recno;
  1914. rce->key.mv_size = key.mv_size;
  1915. rce->key.mv_data = &rce[1];
  1916. rce->data.mv_size = data.mv_size;
  1917. rce->data.mv_data = ((char*)&rce[1])+rce->key.mv_size;
  1918. memcpy(rce->key.mv_data, key.mv_data, key.mv_size);
  1919. memcpy(rce->data.mv_data, data.mv_data, data.mv_size);
  1920. rcdata.mv_data = rce;
  1921. rcdata.mv_size = len;
  1922. dbmdb_generate_recno_cache_key_by_recno(&rckey, recno);
  1923. rc = MDB_PUT(txn_ctx.txn, rcctx->rcdbi->dbi, &rckey, &rcdata, 0);
  1924. slapi_ch_free(&rckey.mv_data);
  1925. if (rc == 0) {
  1926. dbmdb_generate_recno_cache_key_by_data(&rckey, &key, &data);
  1927. rc = MDB_PUT(txn_ctx.txn, rcctx->rcdbi->dbi, &rckey, &rcdata, 0);
  1928. slapi_ch_free(&rckey.mv_data);
  1929. txn_ctx.flags |= DBMDB_TXNCTX_NEED_COMMIT;
  1930. }
  1931. slapi_ch_free(&rcdata.mv_data);
  1932. rc = MDB_CURSOR_GET(txn_ctx.cursor, &key, &data, MDB_NEXT);
  1933. recno++;
  1934. }
  1935. if (rc == MDB_NOTFOUND) {
  1936. /* Mark the cache as valid */
  1937. rckey.mv_data = "OK";
  1938. rckey.mv_size = 2;
  1939. rc = MDB_PUT(txn_ctx.txn, rcctx->rcdbi->dbi, &rckey, &rckey, 0);
  1940. txn_ctx.flags |= DBMDB_TXNCTX_NEED_COMMIT;
  1941. }
  1942. cache_built:
  1943. rc = dbmdb_end_recno_cache_txn(&txn_ctx, rc);
  1944. if (rc == 0) {
  1945. rc = dbmdb_recno_cache_search(rcctx);
  1946. }
  1947. rcctx->rc = rc;
  1948. return NULL;
  1949. }
  1950. /* Find nearest recno cache record from the key */
  1951. int dbmdb_recno_cache_lookup(dbi_cursor_t *cursor, MDB_val *cache_key, dbmdb_recno_cache_elmt_t **rce)
  1952. {
  1953. dbmdb_recno_cache_ctx_t rcctx = {0};
  1954. struct ldbminfo *li = (struct ldbminfo *)cursor->be->be_database->plg_private;
  1955. dbmdb_ctx_t *ctx = MDB_CONFIG(li);
  1956. int rc = 0;
  1957. rcctx.cursor = cursor;
  1958. rcctx.cache_key = *cache_key;
  1959. rc = dbmdb_recno_cache_get_mode(&rcctx);
  1960. if (rc) {
  1961. return rc;
  1962. }
  1963. if (rcctx.mode == RCMODE_USE_CURSOR_TXN) {
  1964. rc = dbmdb_recno_cache_search(&rcctx);
  1965. } else if (rcctx.mode != RCMODE_UNKNOWN) {
  1966. pthread_mutex_lock(&ctx->rcmutex);
  1967. slapi_ch_free_string(&rcctx.rcdbname);
  1968. rc = dbmdb_recno_cache_get_mode(&rcctx); /* Try again while the lock is held */
  1969. if (rcctx.mode == RCMODE_USE_CURSOR_TXN) {
  1970. rc = dbmdb_recno_cache_search(&rcctx);
  1971. } else if (rcctx.mode == RCMODE_USE_SUBTXN) {
  1972. dbmdb_recno_cache_build(&rcctx);
  1973. rc = rcctx.rc;
  1974. } else if (rcctx.mode == RCMODE_USE_NEW_THREAD) {
  1975. pthread_t tid;
  1976. rc = pthread_create(&tid, NULL, dbmdb_recno_cache_build, &rcctx);
  1977. if (rc ==0) {
  1978. rc = pthread_join(tid, NULL);
  1979. }
  1980. if (rc ==0) {
  1981. rc = rcctx.rc;
  1982. }
  1983. }
  1984. pthread_mutex_unlock(&ctx->rcmutex);
  1985. }
  1986. *rce = rcctx.rce;
  1987. if (!rcctx.rce) {
  1988. rc = MDB_NOTFOUND;
  1989. }
  1990. slapi_ch_free_string(&rcctx.rcdbname);
  1991. return rc;
  1992. }
  1993. int dbmdb_cmp_vals(MDB_val *v1, MDB_val *v2)
  1994. {
  1995. int l = v1->mv_size;
  1996. int rc;
  1997. if (l > v2->mv_size) {
  1998. l = v2->mv_size;
  1999. }
  2000. rc = memcmp(v1->mv_data, v2->mv_data, l);
  2001. if (rc == 0) {
  2002. rc = v1->mv_size - v2->mv_size;
  2003. }
  2004. return rc;
  2005. }
  2006. int dbmdb_cmp_dbi_record(MDB_dbi dbi, MDB_val *key1, MDB_val *data1, MDB_val *key2, MDB_val *data2)
  2007. {
  2008. int rc = 0;
  2009. int n1 = key1 && key1->mv_data && key1->mv_size;
  2010. int n2 = key2 && key2->mv_data && key2->mv_size;
  2011. rc = n1 - n2 ;
  2012. if (rc == 0) {
  2013. rc = dbmdb_cmp_vals(key1, key2);
  2014. }
  2015. if (rc == 0) {
  2016. n1 = data1 && data1->mv_data && data1->mv_size;
  2017. n2 = data2 && data2->mv_data && data2->mv_size;
  2018. rc = n1 - n2 ;
  2019. }
  2020. if (rc == 0) {
  2021. rc = dbmdb_cmp_vals(data1, data2);
  2022. }
  2023. return rc;
  2024. }
  2025. /* Get current cursor recno - i.e: data is set to current recno */
  2026. int dbmdb_cursor_get_recno(dbi_cursor_t *cursor, MDB_val *dbmdb_key, MDB_val *dbmdb_data)
  2027. {
  2028. dbmdb_recno_cache_elmt_t *rce = NULL;
  2029. MDB_val curpos_key = {0};
  2030. MDB_val curpos_data = {0};
  2031. MDB_val cache_key = {0};
  2032. MDB_cursor *newcur = NULL;
  2033. int cmpres = 0;
  2034. int rc = 0;
  2035. rc = MDB_CURSOR_GET(cursor->cur, &curpos_key, &curpos_data, MDB_GET_CURRENT);
  2036. if (rc != 0) {
  2037. return rc;
  2038. }
  2039. dbmdb_generate_recno_cache_key_by_data(&cache_key, &curpos_key, &curpos_data);
  2040. rc = dbmdb_recno_cache_lookup(cursor, &cache_key, &rce);
  2041. if (rc == 0) {
  2042. rc = MDB_CURSOR_OPEN(mdb_cursor_txn(cursor->cur), mdb_cursor_dbi(cursor->cur), &newcur);
  2043. }
  2044. if (rc == 0) {
  2045. rc = MDB_CURSOR_GET(newcur, &rce->key, &rce-> data, MDB_SET);
  2046. }
  2047. while (rc == 0) {
  2048. cmpres = dbmdb_cmp_dbi_record(mdb_cursor_dbi(cursor->cur), &curpos_key, &curpos_data, &rce->key, &rce->data);
  2049. if (cmpres >= 0) {
  2050. break;
  2051. }
  2052. rce->recno++;
  2053. rc = MDB_CURSOR_GET(newcur, &rce->key, &rce->data, MDB_NEXT);
  2054. }
  2055. if (cmpres > 0) {
  2056. rc = MDB_NOTFOUND;
  2057. }
  2058. if (rc == 0) {
  2059. if (dbmdb_data->mv_data == NULL || dbmdb_data->mv_size != sizeof (dbi_recno_t)) {
  2060. dbmdb_data->mv_size = sizeof (dbi_recno_t);
  2061. dbmdb_data->mv_data = slapi_ch_calloc(1, dbmdb_data->mv_size);
  2062. }
  2063. memcpy(dbmdb_data->mv_data, &rce->recno, dbmdb_data->mv_size);
  2064. }
  2065. slapi_ch_free((void**)&rce);
  2066. return rc;
  2067. }
  2068. /* Move cursor to recno */
  2069. int dbmdb_cursor_set_recno(dbi_cursor_t *cursor, MDB_val *dbmdb_key, MDB_val *dbmdb_data)
  2070. {
  2071. dbmdb_recno_cache_elmt_t *rce = NULL;
  2072. MDB_val cache_key = {0};
  2073. dbi_recno_t recno;
  2074. int rc;
  2075. memcpy(&recno, dbmdb_data->mv_data, sizeof (dbi_recno_t));
  2076. dbmdb_generate_recno_cache_key_by_recno(&cache_key, recno);
  2077. rc = dbmdb_recno_cache_lookup(cursor, &cache_key, &rce);
  2078. if (rc ==0) {
  2079. rc = MDB_CURSOR_GET(cursor->cur, &rce->key, &rce->data, MDB_SET_RANGE);
  2080. }
  2081. while (rc == 0 && recno > rce->recno) {
  2082. rce->recno++;
  2083. rc = MDB_CURSOR_GET(cursor->cur, &rce->key, &rce->data, MDB_NEXT);
  2084. }
  2085. if (dbmdb_data->mv_size == rce->data.mv_size) {
  2086. /* Should always be the case */
  2087. memcpy(dbmdb_data->mv_data , rce->data.mv_data, dbmdb_data->mv_size);
  2088. }
  2089. slapi_ch_free((void**)&rce);
  2090. return rc;
  2091. }
  2092. int dbmdb_public_cursor_op(dbi_cursor_t *cursor, dbi_op_t op, dbi_val_t *key, dbi_val_t *data)
  2093. {
  2094. MDB_cursor *dbmdb_cur = (MDB_cursor*)cursor->cur;
  2095. MDB_val dbmdb_key = {0};
  2096. MDB_val dbmdb_data = {0};
  2097. uint flags = 0;
  2098. int rc = 0;
  2099. if (dbmdb_cur == NULL) {
  2100. return (op == DBI_OP_CLOSE) ? DBI_RC_SUCCESS : DBI_RC_INVALID;
  2101. }
  2102. dbmdb_dbival2dbt(key, &dbmdb_key, PR_FALSE);
  2103. dbmdb_dbival2dbt(data, &dbmdb_data, PR_FALSE);
  2104. switch (op)
  2105. {
  2106. case DBI_OP_MOVE_TO_KEY:
  2107. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_SET);
  2108. break;
  2109. case DBI_OP_MOVE_NEAR_KEY:
  2110. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_SET_RANGE);
  2111. break;
  2112. case DBI_OP_MOVE_TO_DATA:
  2113. rc = mdb_dbi_flags(mdb_cursor_txn(dbmdb_cur), mdb_cursor_dbi(dbmdb_cur), &flags);
  2114. if (rc == 0) {
  2115. if (flags & MDB_DUPSORT) {
  2116. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_GET_BOTH);
  2117. } else {
  2118. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_SET);
  2119. }
  2120. }
  2121. break;
  2122. case DBI_OP_MOVE_NEAR_DATA:
  2123. rc = mdb_dbi_flags(mdb_cursor_txn(dbmdb_cur), mdb_cursor_dbi(dbmdb_cur), &flags);
  2124. if (rc == 0) {
  2125. if (flags & MDB_DUPSORT) {
  2126. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_GET_BOTH_RANGE);
  2127. } else {
  2128. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_SET_RANGE);
  2129. }
  2130. }
  2131. break;
  2132. case DBI_OP_MOVE_TO_RECNO:
  2133. rc = dbmdb_cursor_set_recno(cursor, &dbmdb_key, &dbmdb_data);
  2134. break;
  2135. case DBI_OP_MOVE_TO_FIRST:
  2136. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_FIRST);
  2137. break;
  2138. case DBI_OP_MOVE_TO_LAST:
  2139. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_LAST);
  2140. break;
  2141. case DBI_OP_GET:
  2142. /* not a dbmdb_cur operation (db operation) */
  2143. PR_ASSERT(op != DBI_OP_GET);
  2144. rc = DBI_RC_UNSUPPORTED;
  2145. break;
  2146. case DBI_OP_GET_RECNO:
  2147. rc = dbmdb_cursor_get_recno(cursor, &dbmdb_key, &dbmdb_data);
  2148. break;
  2149. case DBI_OP_NEXT:
  2150. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_NEXT);
  2151. break;
  2152. case DBI_OP_NEXT_DATA:
  2153. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_NEXT_DUP);
  2154. break;
  2155. case DBI_OP_NEXT_KEY:
  2156. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_NEXT_NODUP);
  2157. break;
  2158. case DBI_OP_PREV:
  2159. rc = MDB_CURSOR_GET(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_PREV);
  2160. break;
  2161. case DBI_OP_PUT:
  2162. /* not a dbmdb_cur operation (db operation) */
  2163. PR_ASSERT(op != DBI_OP_PUT);
  2164. rc = DBI_RC_UNSUPPORTED;
  2165. break;
  2166. case DBI_OP_REPLACE:
  2167. rc = MDB_CURSOR_PUT(dbmdb_cur, &dbmdb_key, &dbmdb_data, MDB_CURRENT);
  2168. break;
  2169. case DBI_OP_ADD:
  2170. rc = MDB_CURSOR_PUT(dbmdb_cur, &dbmdb_key, &dbmdb_data, 0);
  2171. break;
  2172. case DBI_OP_DEL:
  2173. rc = mdb_cursor_del(dbmdb_cur, 0);
  2174. break;
  2175. case DBI_OP_CLOSE:
  2176. MDB_CURSOR_CLOSE(dbmdb_cur);
  2177. if (cursor->islocaltxn) {
  2178. /* local txn is read only and should be aborted when closing the cursor */
  2179. END_TXN(&cursor->txn, 1);
  2180. }
  2181. break;
  2182. default:
  2183. /* Unknown operation */
  2184. PR_ASSERT(op != op);
  2185. rc = DBI_RC_UNSUPPORTED;
  2186. break;
  2187. }
  2188. rc = dbmdb_map_error(__FUNCTION__, rc);
  2189. rc = dbmdb_dbt2dbival(&dbmdb_key, key, PR_TRUE, rc);
  2190. rc = dbmdb_dbt2dbival(&dbmdb_data, data, PR_TRUE, rc);
  2191. return rc;
  2192. }
  2193. int dbmdb_public_db_op(dbi_db_t *db, dbi_txn_t *txn, dbi_op_t op, dbi_val_t *key, dbi_val_t *data)
  2194. {
  2195. MDB_val dbmdb_key = {0};
  2196. MDB_val dbmdb_data = {0};
  2197. MDB_txn *mdb_txn = TXN(txn);
  2198. dbmdb_dbi_t *dbmdb_db = (dbmdb_dbi_t*)db;
  2199. MDB_dbi dbi = dbmdb_db->dbi;
  2200. dbi_txn_t *ltxn = NULL;
  2201. int rc = 0;
  2202. dbmdb_dbival2dbt(key, &dbmdb_key, PR_FALSE);
  2203. dbmdb_dbival2dbt(data, &dbmdb_data, PR_FALSE);
  2204. if (!txn) {
  2205. rc = START_TXN(&ltxn, NULL, ((op == DBI_OP_GET) ? TXNFL_RDONLY : 0));
  2206. mdb_txn = TXN(ltxn);
  2207. }
  2208. switch (op)
  2209. {
  2210. case DBI_OP_GET:
  2211. rc = MDB_GET(mdb_txn, dbi, &dbmdb_key, &dbmdb_data);
  2212. break;
  2213. case DBI_OP_PUT:
  2214. rc = MDB_PUT(mdb_txn, dbi, &dbmdb_key, &dbmdb_data, 0);
  2215. break;
  2216. case DBI_OP_ADD:
  2217. rc = MDB_PUT(mdb_txn, dbi, &dbmdb_key, &dbmdb_data, 0);
  2218. break;
  2219. case DBI_OP_DEL:
  2220. rc = MDB_DEL(mdb_txn, dbi, &dbmdb_key, dbmdb_data.mv_data ? &dbmdb_data : NULL);
  2221. break;
  2222. case DBI_OP_CLOSE:
  2223. /* No need to close db instances with lmdb */
  2224. break;
  2225. default:
  2226. /* Unknown db operation */
  2227. PR_ASSERT(op != op);
  2228. rc = DBI_RC_UNSUPPORTED;
  2229. break;
  2230. }
  2231. if (ltxn) {
  2232. rc = END_TXN(&ltxn, rc);
  2233. }
  2234. rc = dbmdb_map_error(__FUNCTION__, rc);
  2235. rc = dbmdb_dbt2dbival(&dbmdb_key, key, PR_TRUE, rc);
  2236. rc = dbmdb_dbt2dbival(&dbmdb_data, data, PR_TRUE, rc);
  2237. return rc;
  2238. }
  2239. int dbmdb_public_new_cursor(dbi_db_t *db, dbi_cursor_t *cursor)
  2240. {
  2241. dbmdb_dbi_t *dbi = (dbmdb_dbi_t*) db;
  2242. int rc = 0;
  2243. cursor->islocaltxn = PR_FALSE;
  2244. if (!cursor->txn) {
  2245. /* No txn is provided so it is a read only cursor
  2246. * Let checks if a txn has been pushed on thread
  2247. * use it if that is the case
  2248. * otherwise begin a new local txn
  2249. */
  2250. rc = START_TXN(&cursor->txn, NULL, TXNFL_RDONLY);
  2251. if (rc) {
  2252. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_new_cursor",
  2253. "Failed to get a local txn while opening a cursor on db %s . rc=%d %s\n",
  2254. dbi->dbname, rc, mdb_strerror(rc));
  2255. return dbmdb_map_error(__FUNCTION__, rc);
  2256. }
  2257. cursor->islocaltxn = PR_TRUE;
  2258. }
  2259. rc = MDB_CURSOR_OPEN(TXN(cursor->txn), dbi->dbi, (MDB_cursor**)&cursor->cur);
  2260. if (rc==EINVAL) { /* DBG txn or dbi error */
  2261. MDB_stat st2;
  2262. rc = mdb_stat(TXN(cursor->txn), dbi->dbi, &st2);
  2263. if (rc == 0 && st2.ms_entries == 0 && dbmdb_is_read_only_txn_thread()) {
  2264. /* cannot open a cursor with read-only txn on empty db */
  2265. rc = MDB_NOTFOUND;
  2266. } else if (rc==EINVAL) {
  2267. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_new_cursor", "Invalid dbi =%d (%s) while opening cursor in txn= %p\n", dbi->dbi, dbi->dbname, TXN(cursor->txn));
  2268. log_stack(SLAPI_LOG_ERR);
  2269. } else {
  2270. rc = EINVAL;
  2271. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_new_cursor", "Failed to open cursor dbi =%d (%s) in txn= %p\n", dbi->dbi, dbi->dbname, TXN(cursor->txn));
  2272. log_stack(SLAPI_LOG_ERR);
  2273. }
  2274. }
  2275. if (rc && cursor->islocaltxn)
  2276. END_TXN(&cursor->txn, rc);
  2277. return dbmdb_map_error(__FUNCTION__, rc);
  2278. }
  2279. int dbmdb_public_value_free(dbi_val_t *data)
  2280. {
  2281. /* No specific action required for mdb db handling */
  2282. return DBI_RC_SUCCESS;
  2283. }
  2284. int dbmdb_public_value_init(dbi_val_t *data)
  2285. {
  2286. /* No specific action required for mdb db handling */
  2287. return DBI_RC_SUCCESS;
  2288. }
  2289. int
  2290. dbmdb_public_set_dup_cmp_fn(struct attrinfo *a, dbi_dup_cmp_t idx)
  2291. {
  2292. /*
  2293. * Do nothing here - dbmdb_entryrdn_compare_dups is now set
  2294. * at dbmdb_open_dbname level (so it get also set for dbscan)
  2295. */
  2296. return 0;
  2297. }
  2298. int
  2299. dbmdb_dbi_txn_begin(dbi_env_t *env, PRBool readonly, dbi_txn_t *parent_txn, dbi_txn_t **txn)
  2300. {
  2301. int rc = START_TXN(txn, parent_txn, (readonly?TXNFL_RDONLY:0));
  2302. return dbmdb_map_error(__FUNCTION__, rc);
  2303. }
  2304. int
  2305. dbmdb_dbi_txn_commit(dbi_txn_t *txn)
  2306. {
  2307. int rc = END_TXN(&txn, 0);
  2308. return dbmdb_map_error(__FUNCTION__, rc);
  2309. }
  2310. int
  2311. dbmdb_dbi_txn_abort(dbi_txn_t *txn)
  2312. {
  2313. END_TXN(&txn, 1);
  2314. return 0;
  2315. }
  2316. int
  2317. dbmdb_get_entries_count(dbi_db_t *db, dbi_txn_t *txn, int *count)
  2318. {
  2319. dbmdb_dbi_t *dbmdb_db = (dbmdb_dbi_t*)db;
  2320. MDB_stat stats = {0};
  2321. int rc = 0;
  2322. rc = START_TXN(&txn, txn, TXNFL_RDONLY);
  2323. if (rc == 0)
  2324. rc = mdb_stat(TXN(txn), dbmdb_db->dbi, &stats);
  2325. if (rc == 0)
  2326. *count = stats.ms_entries;
  2327. END_TXN(&txn, 1);
  2328. return dbmdb_map_error(__FUNCTION__, rc);
  2329. }
  2330. /* Get the number of duplicates for current key */
  2331. int
  2332. dbmdb_public_cursor_get_count(dbi_cursor_t *cursor, dbi_recno_t *count)
  2333. {
  2334. size_t c = 0;
  2335. MDB_cursor *cur = cursor->cur;
  2336. int rc = mdb_cursor_count(cur, &c);
  2337. *count = c;
  2338. return dbmdb_map_error(__FUNCTION__, rc);
  2339. }
  2340. int find_mdb_home(const char *db_filename, char *home, const char **dbname)
  2341. {
  2342. struct stat st;
  2343. const char *pt2;
  2344. char *pt;
  2345. strncpy(home, db_filename, MAXPATHLEN-1);
  2346. for(;;) {
  2347. pt = home + strlen(home);
  2348. if (pt+10 >= &home[MAXPATHLEN])
  2349. return DBI_RC_NOTFOUND;
  2350. *pt = '/';
  2351. strcpy(pt+1, DBMAPFILE);
  2352. if (stat(home, &st) == 0) {
  2353. /* Found dbhome */
  2354. *pt = 0;
  2355. break;
  2356. }
  2357. /* Try again with upper directory */
  2358. *pt = 0;
  2359. pt = strrchr(home, '/');
  2360. if (!pt)
  2361. return DBI_RC_NOTFOUND;
  2362. *pt = 0;
  2363. }
  2364. pt2 = db_filename+(pt-home);
  2365. while (*pt2 == '/')
  2366. pt2++;
  2367. *dbname = pt2;
  2368. return *pt2 ? 0 : DBI_RC_NOTFOUND;
  2369. }
  2370. int
  2371. dbmdb_public_private_open(backend *be, const char *db_filename, int rw, dbi_env_t **env, dbi_db_t **db)
  2372. {
  2373. struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
  2374. dbmdb_ctx_t *ctx = (dbmdb_ctx_t*) slapi_ch_calloc(1, sizeof *ctx);
  2375. dbmdb_dbi_t *dbi = NULL;
  2376. const char *dbname = NULL;
  2377. li->li_dblayer_config = ctx;
  2378. int rc = find_mdb_home(db_filename, ctx->home, &dbname);
  2379. if (rc)
  2380. return DBI_RC_NOTFOUND;
  2381. rc = dbmdb_make_env(ctx, rw?0:1, 0644);
  2382. if (rc) {
  2383. return dbmdb_map_error(__FUNCTION__, rc);
  2384. }
  2385. *env = ctx->env;
  2386. rc = dbmdb_open_dbi_from_filename(&dbi, be, dbname, NULL, MDB_OPEN_DIRTY_DBI | rw ? MDB_CREATE : 0);
  2387. if (rc) {
  2388. return dbmdb_map_error(__FUNCTION__, rc);
  2389. }
  2390. *db = (dbi_db_t *)dbi;
  2391. return 0;
  2392. }
  2393. int
  2394. dbmdb_public_private_close(dbi_env_t **env, dbi_db_t **db)
  2395. {
  2396. if (*db)
  2397. dbmdb_public_db_op(*db, NULL, DBI_OP_CLOSE, NULL, NULL);
  2398. *db = NULL;
  2399. if (*env)
  2400. mdb_env_close((MDB_env*)*env);
  2401. *env = NULL;
  2402. return 0;
  2403. }
  2404. static int
  2405. dbmdb_force_checkpoint(struct ldbminfo *li)
  2406. {
  2407. dbmdb_ctx_t *ctx = MDB_CONFIG(li);
  2408. int rc = mdb_env_sync(ctx->env, 1);
  2409. return dbmdb_map_error(__FUNCTION__, rc);
  2410. }
  2411. /* check whether import is executed (or aborted) by other process or not */
  2412. int
  2413. dbmdb_public_in_import(ldbm_instance *inst)
  2414. {
  2415. struct ldbminfo *li = inst->inst_li;
  2416. dbmdb_ctx_t *ctx = MDB_CONFIG(li);
  2417. dbmdb_dbi_t **dbilist = NULL;
  2418. int size = 0;
  2419. int rval = 0;
  2420. int i;
  2421. dbilist = dbmdb_list_dbis(ctx, inst->inst_be, NULL, PR_FALSE, &size);
  2422. for (i=0; i<size; i++) {
  2423. if (dbilist[i]->state.state & DBIST_DIRTY) {
  2424. rval = 1;
  2425. break;
  2426. }
  2427. }
  2428. slapi_ch_free((void **)&dbilist);
  2429. return rval;
  2430. }
  2431. const char *
  2432. dbmdb_public_get_db_suffix(void)
  2433. {
  2434. return LDBM_FILENAME_SUFFIX;
  2435. }
  2436. int
  2437. dbmdb_public_dblayer_compact(Slapi_Backend *be, PRBool just_changelog)
  2438. {
  2439. struct ldbminfo *li = NULL;
  2440. Slapi_Backend *be1 = NULL;
  2441. dbmdb_ctx_t *ctx = NULL;
  2442. char *newdb_name = NULL;
  2443. char *db_name = NULL;
  2444. char *cookie = NULL;
  2445. int newdb_fd = -1;
  2446. Slapi_PBlock *pb;
  2447. int32_t rc = -1;
  2448. /* dbmdb_public_dblayer_compact is called in loop (walking all non private backends)
  2449. * but as mdb database is common for all backends we should only compact once
  2450. * so let's do it only for first backend.
  2451. */
  2452. be1 = slapi_get_first_backend(&cookie);
  2453. while (be1 && be1->be_private) {
  2454. be1 = (backend *)slapi_get_next_backend(cookie);
  2455. }
  2456. slapi_ch_free_string(&cookie);
  2457. if (be != be1) {
  2458. return 0;
  2459. }
  2460. slapi_log_err(SLAPI_LOG_NOTICE, "dbmdb_public_dblayer_compact",
  2461. "Compacting databases ...\n");
  2462. pb = slapi_pblock_new();
  2463. slapi_pblock_set(pb, SLAPI_PLUGIN, (be->be_database));
  2464. slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
  2465. ctx = MDB_CONFIG(li);
  2466. db_name = slapi_ch_smprintf("%s/%s", ctx->home, DBMAPFILE);
  2467. newdb_name = slapi_ch_smprintf("%s/%s.bak", ctx->home, DBMAPFILE);
  2468. newdb_fd = open(newdb_name, O_CREAT|O_WRONLY|O_TRUNC, li->li_mode | 0600);
  2469. if (newdb_fd < 0) {
  2470. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_dblayer_compact",
  2471. "Failed to create database copy. Error is %d, File is %s\n",
  2472. errno, newdb_name);
  2473. slapi_ch_free_string(&newdb_name);
  2474. return -1;
  2475. }
  2476. rc = ldbm_temporary_close_all_instances(pb);
  2477. if (!rc) {
  2478. goto out;
  2479. }
  2480. rc = mdb_env_copyfd2(ctx->env, newdb_fd, MDB_CP_COMPACT);
  2481. if (!rc) {
  2482. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_dblayer_compact",
  2483. "Failed to compact the database. Error is %d (%s), File is %s\n",
  2484. rc, mdb_strerror(rc), newdb_name);
  2485. goto out;
  2486. }
  2487. rc = close(newdb_fd);
  2488. if (!rc) {
  2489. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_dblayer_compact",
  2490. "Failed to close the database copy. Error is %d, File is %s\n",
  2491. errno, newdb_name);
  2492. goto out;
  2493. }
  2494. /* Close the mdb env and release the plugin resources */
  2495. dbmdb_ctx_close(ctx);
  2496. rc = rename (newdb_name, db_name);
  2497. if (!rc) {
  2498. slapi_log_err(SLAPI_LOG_ERR, "dbmdb_public_dblayer_compact",
  2499. "Failed to rename the database copy from %s to %s. Error is %d\n",
  2500. newdb_name, db_name, errno);
  2501. }
  2502. /* reopen the mdb env and initialize the plugin resources */
  2503. mdb_init(li, NULL);
  2504. out:
  2505. rc = ldbm_restart_temporary_closed_instances(pb);
  2506. slapi_pblock_destroy(pb);
  2507. if (newdb_fd>=0) {
  2508. close(newdb_fd);
  2509. }
  2510. if (newdb_name) {
  2511. unlink(newdb_name);
  2512. slapi_ch_free_string(&newdb_name);
  2513. }
  2514. slapi_ch_free_string(&db_name);
  2515. slapi_log_err(SLAPI_LOG_NOTICE, "dbmdb_public_dblayer_compact",
  2516. "Compacting databases finished.\n");
  2517. return rc;
  2518. }
  2519. int
  2520. dbmdb_public_clear_vlv_cache(Slapi_Backend *be, dbi_txn_t *txn, dbi_db_t *db)
  2521. {
  2522. char *rcdbname = slapi_ch_smprintf("%s%s", RECNOCACHE_PREFIX, ((dbmdb_dbi_t*)db)->dbname);
  2523. dbmdb_dbi_t *rcdbi = NULL;
  2524. MDB_val ok = { 0 };
  2525. int rc = 0;
  2526. ok.mv_data = "OK";
  2527. ok.mv_size = 2;
  2528. rc = dbmdb_open_dbi_from_filename(&rcdbi, be, rcdbname, NULL, 0);
  2529. if (rc == 0) {
  2530. rc = MDB_DEL(TXN(txn), rcdbi->dbi, &ok, &ok);
  2531. }
  2532. slapi_ch_free_string(&rcdbname);
  2533. return rc;
  2534. }
  2535. int
  2536. dbmdb_public_delete_db(Slapi_Backend *be, dbi_db_t *db)
  2537. {
  2538. struct ldbminfo *li = (struct ldbminfo *)(be->be_database->plg_private);
  2539. dbmdb_ctx_t *ctx = MDB_CONFIG(li);
  2540. return dbmdb_dbi_remove(ctx, &db);
  2541. }
  2542. IDList *
  2543. dbmdb_idl_new_fetch(backend *be, dbi_db_t *db, dbi_val_t *inkey, dbi_txn_t *txn, struct attrinfo *a, int *flag_err, int allidslimit)
  2544. {
  2545. char *index_id = get_index_name(be, db, a);
  2546. MDB_cursor *cursor = NULL;
  2547. dbi_txn_t *s_txn = NULL;
  2548. IDList *idl = NULL;
  2549. dbmdb_dbi_t *dbi = db;
  2550. MDB_val data = {0};
  2551. MDB_val key = {0};
  2552. size_t count = 0;
  2553. int rc = 0;
  2554. dbmdb_dbival2dbt(inkey, &key, PR_FALSE);
  2555. rc = START_TXN(&s_txn, txn, TXNFL_RDONLY);
  2556. if (rc) {
  2557. ldbm_nasty("dbmdb_idl_new_fetch - idl_new.c", index_id, 110, rc);
  2558. goto error;
  2559. }
  2560. rc = MDB_CURSOR_OPEN(TXN(s_txn), dbi->dbi, &cursor);
  2561. if (rc) {
  2562. ldbm_nasty("dbmdb_idl_new_fetch - idl_new.c", index_id, 120, rc);
  2563. goto error;
  2564. }
  2565. rc = MDB_CURSOR_GET(cursor, &key, &data, MDB_SET_KEY);
  2566. if (rc == 0) {
  2567. rc = MDB_CURSOR_GET(cursor, &key, &data, MDB_FIRST_DUP);
  2568. }
  2569. if (rc == 0) {
  2570. rc = mdb_cursor_count(cursor, &count);
  2571. if (rc) {
  2572. ldbm_nasty("dbmdb_idl_new_fetch - idl_new.c", index_id, 130, rc);
  2573. goto error;
  2574. }
  2575. }
  2576. if (allidslimit && count >= allidslimit) {
  2577. idl = idl_allids(be);
  2578. slapi_log_err(SLAPI_LOG_TRACE, "dbmdb_idl_new_fetch", "%s returns allids (attribute: %s)\n",
  2579. (char *)key.mv_data, index_id);
  2580. goto error;
  2581. }
  2582. /* Allocate an idlist to populate into */
  2583. if (count>0) {
  2584. idl = idl_alloc(count);
  2585. } else {
  2586. idl = idl_alloc(IDLIST_MIN_BLOCK_SIZE);
  2587. }
  2588. while (rc == 0) {
  2589. idl_append_extend(&idl, *(ID*)data.mv_data);
  2590. rc = MDB_CURSOR_GET(cursor, &key, &data, MDB_NEXT_DUP);
  2591. }
  2592. if (rc == MDB_NOTFOUND) {
  2593. rc = 0;
  2594. }
  2595. error:
  2596. if (cursor) {
  2597. MDB_CURSOR_CLOSE(cursor);
  2598. }
  2599. if (s_txn) {
  2600. rc = END_TXN(&s_txn, rc);
  2601. }
  2602. if (rc) {
  2603. idl_free(&idl);
  2604. }
  2605. /* check for allids value */
  2606. if (idl == NULL) {
  2607. slapi_log_err(SLAPI_LOG_TRACE, "dbmdb_idl_new_fetch", "%s failed (attribute: %s). error is %d (%s).\n",
  2608. (char *)key.mv_data, index_id, rc, mdb_strerror(rc));
  2609. } else if (idl->b_nids == 1 && idl->b_ids[0] == ALLID) {
  2610. slapi_log_err(SLAPI_LOG_TRACE, "dbmdb_idl_new_fetch", "%s returns allids (attribute: %s)\n",
  2611. (char *)key.mv_data, index_id);
  2612. } else {
  2613. slapi_log_err(SLAPI_LOG_TRACE, "dbmdb_idl_new_fetch", "%s returns nids=%lu (attribute: %s)\n",
  2614. (char *)key.mv_data, (u_long)IDL_NIDS(idl), index_id);
  2615. }
  2616. *flag_err = rc;
  2617. return idl;
  2618. }