upgrade.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* upgrade.c --- upgrade from a previous version of the database */
  42. #include "back-ldbm.h"
  43. /*
  44. * ldbm_compat_versions holds DBVERSION strings for all versions of the
  45. * database with which we are (upwards) compatible. If check_db_version
  46. * encounters a database with a version that is not listed in this array,
  47. * we display a warning message.
  48. */
  49. db_upgrade_info ldbm_version_suss[] = {
  50. /* for bdb/#.#/..., we don't have to put the version number in the 2nd col
  51. since DBVERSION keeps it */
  52. {BDB_IMPL, 0, 0, DBVERSION_NEW_IDL, DBVERSION_NO_UPGRADE},
  53. {LDBM_VERSION, 4, 2, DBVERSION_NEW_IDL, DBVERSION_NO_UPGRADE},
  54. {LDBM_VERSION_OLD, 4, 2, DBVERSION_OLD_IDL, DBVERSION_NO_UPGRADE},
  55. {LDBM_VERSION_62, 4, 2, DBVERSION_OLD_IDL, DBVERSION_NO_UPGRADE},
  56. {LDBM_VERSION_61, 3, 3, DBVERSION_OLD_IDL, DBVERSION_UPGRADE_3_4},
  57. {LDBM_VERSION_60, 3, 3, DBVERSION_OLD_IDL, DBVERSION_UPGRADE_3_4},
  58. {NULL,0,0}
  59. };
  60. /* clear the following flag to suppress "database files do not exist" warning
  61. int ldbm_warn_if_no_db = 0;
  62. */
  63. /* global LDBM version in the db home */
  64. int
  65. lookup_dbversion(char *dbversion, int flag)
  66. {
  67. int i, matched = 0;
  68. int rval = DBVERSION_NO_UPGRADE;
  69. for ( i = 0; ldbm_version_suss[i].old_version_string != NULL; ++i )
  70. {
  71. if (PL_strncasecmp(dbversion, ldbm_version_suss[i].old_version_string,
  72. strlen(ldbm_version_suss[i].old_version_string)) == 0)
  73. {
  74. matched = 1;
  75. break;
  76. }
  77. }
  78. if ( matched )
  79. {
  80. if ( flag & DBVERSION_TYPE )
  81. {
  82. rval |= ldbm_version_suss[i].type;
  83. }
  84. if ( flag & DBVERSION_ACTION )
  85. {
  86. int dbmajor = 0, dbminor = 0;
  87. if (0 == ldbm_version_suss[i].old_dbversion_major)
  88. {
  89. /* case of bdb/#.#/... */
  90. char *p = strchr(dbversion, '/');
  91. char *endp = dbversion + strlen(dbversion);
  92. if (NULL != p && p < endp)
  93. {
  94. char *dotp = strchr(++p, '.');
  95. if (NULL != dotp)
  96. {
  97. *dotp = '\0';
  98. dbmajor = strtol(p, (char **)NULL, 10);
  99. dbminor = strtol(++dotp, (char **)NULL, 10);
  100. }
  101. else
  102. {
  103. dbmajor = strtol(p, (char **)NULL, 10);
  104. }
  105. }
  106. }
  107. else
  108. {
  109. dbmajor = ldbm_version_suss[i].old_dbversion_major;
  110. dbminor = ldbm_version_suss[i].old_dbversion_minor;
  111. }
  112. if (dbmajor < DB_VERSION_MAJOR)
  113. {
  114. /* 3.3 -> 4.x */
  115. rval |= ldbm_version_suss[i].action;
  116. }
  117. else if (dbminor < DB_VERSION_MINOR)
  118. {
  119. /* 4.low -> 4.high */
  120. rval |= DBVERSION_UPGRADE_4_4;
  121. }
  122. }
  123. }
  124. return rval;
  125. }
  126. /*
  127. * this function reads the db/DBVERSION file and check
  128. * 1) if the db version is supported, and
  129. * 2) if the db version requires some migration operation
  130. *
  131. * return: 0: supported
  132. * DBVERSION_NOT_SUPPORTED: not supported
  133. *
  134. * action: 0: nothing is needed
  135. * DBVERSION_UPGRADE_3_4: db3->db4 uprev is needed
  136. * DBVERSION_UPGRADE_4_4: db4->db4 uprev is needed
  137. */
  138. int
  139. check_db_version( struct ldbminfo *li, int *action )
  140. {
  141. int value = 0;
  142. char *ldbmversion = NULL;
  143. char *dataversion = NULL;
  144. *action = 0;
  145. dbversion_read(li, li->li_directory, &ldbmversion, &dataversion);
  146. if (NULL == ldbmversion || '\0' == *ldbmversion) {
  147. slapi_ch_free_string(&dataversion);
  148. return 0;
  149. }
  150. value = lookup_dbversion( ldbmversion, DBVERSION_TYPE | DBVERSION_ACTION );
  151. if ( !value )
  152. {
  153. LDAPDebug( LDAP_DEBUG_ANY,
  154. "ERROR: Database version mismatch (expecting "
  155. "'%s' but found '%s' in directory %s)\n",
  156. LDBM_VERSION, ldbmversion, li->li_directory );
  157. /*
  158. * A non-zero return here will cause slapd to exit during startup.
  159. */
  160. slapi_ch_free_string(&ldbmversion);
  161. slapi_ch_free_string(&dataversion);
  162. return DBVERSION_NOT_SUPPORTED;
  163. }
  164. if ( value & DBVERSION_UPGRADE_3_4 )
  165. {
  166. dblayer_set_recovery_required(li);
  167. *action = DBVERSION_UPGRADE_3_4;
  168. }
  169. else if ( value & DBVERSION_UPGRADE_4_4 )
  170. {
  171. dblayer_set_recovery_required(li);
  172. *action = DBVERSION_UPGRADE_4_4;
  173. }
  174. slapi_ch_free_string(&ldbmversion);
  175. slapi_ch_free_string(&dataversion);
  176. return 0;
  177. }
  178. /*
  179. * this function reads the db/<inst>/DBVERSION file and check
  180. * 1) if the db version is supported, and
  181. * 2) if the db version matches the idl configuration
  182. * (nsslapd-idl-switch: new|old)
  183. * note that old idl will disappear from the next major update (6.5? 7.0?)
  184. *
  185. * return: 0: supported and the version matched
  186. * DBVERSION_NEED_IDL_OLD2NEW: old->new uprev is needed
  187. * (used in convindices)
  188. * DBVERSION_NEED_IDL_NEW2OLD: old db is found, for the new idl config
  189. * DBVERSION_NOT_SUPPORTED: not supported
  190. *
  191. * DBVERSION_UPGRADE_3_4: db3->db4 uprev is needed
  192. * DBVERSION_UPGRADE_4_4: db4->db4 uprev is needed
  193. */
  194. int
  195. check_db_inst_version( ldbm_instance *inst )
  196. {
  197. int value = 0;
  198. char *ldbmversion = NULL;
  199. char *dataversion = NULL;
  200. int rval = 0;
  201. char inst_dir[MAXPATHLEN*2];
  202. char *inst_dirp = NULL;
  203. inst_dirp =
  204. dblayer_get_full_inst_dir(inst->inst_li, inst, inst_dir, MAXPATHLEN*2);
  205. dbversion_read(inst->inst_li, inst_dirp, &ldbmversion, &dataversion);
  206. if (NULL == ldbmversion || '\0' == *ldbmversion) {
  207. return rval;
  208. }
  209. value = lookup_dbversion( ldbmversion, DBVERSION_TYPE | DBVERSION_ACTION );
  210. if ( !value )
  211. {
  212. LDAPDebug( LDAP_DEBUG_ANY,
  213. "ERROR: Database version mismatch (expecting "
  214. "'%s' but found '%s' in directory %s)\n",
  215. LDBM_VERSION, ldbmversion, inst->inst_dir_name );
  216. /*
  217. * A non-zero return here will cause slapd to exit during startup.
  218. */
  219. slapi_ch_free_string(&ldbmversion);
  220. slapi_ch_free_string(&dataversion);
  221. return DBVERSION_NOT_SUPPORTED;
  222. }
  223. /* recognize the difference between an old/new database regarding idl
  224. * (406922) */
  225. if (idl_get_idl_new() && !(value & DBVERSION_NEW_IDL) )
  226. {
  227. rval |= DBVERSION_NEED_IDL_OLD2NEW;
  228. }
  229. else if (!idl_get_idl_new() && !(value & DBVERSION_OLD_IDL) )
  230. {
  231. rval |= DBVERSION_NEED_IDL_NEW2OLD;
  232. }
  233. if ( value & DBVERSION_UPGRADE_3_4 )
  234. {
  235. rval |= DBVERSION_UPGRADE_3_4;
  236. }
  237. else if ( value & DBVERSION_UPGRADE_4_4 )
  238. {
  239. rval |= DBVERSION_UPGRADE_4_4;
  240. }
  241. if (inst_dirp != inst_dir)
  242. slapi_ch_free_string(&inst_dirp);
  243. slapi_ch_free_string(&ldbmversion);
  244. slapi_ch_free_string(&dataversion);
  245. return rval;
  246. }
  247. /*
  248. * adjust_idl_switch
  249. * if the current nsslapd-idl-switch is different from ldbmversion,
  250. * update the value of nsslapd-idl-switch (in LDBM_CONFIG_ENTRY)
  251. */
  252. int
  253. adjust_idl_switch(char *ldbmversion, struct ldbminfo *li)
  254. {
  255. int rval = 0;
  256. li->li_flags |= LI_FORCE_MOD_CONFIG;
  257. if ((0 == PL_strncasecmp(ldbmversion, BDB_IMPL, strlen(BDB_IMPL))) ||
  258. (0 == PL_strcmp(ldbmversion, LDBM_VERSION))) /* db: new idl */
  259. {
  260. if (!idl_get_idl_new()) /* config: old idl */
  261. {
  262. replace_ldbm_config_value(CONFIG_IDL_SWITCH, "new", li);
  263. LDAPDebug(LDAP_DEBUG_ANY,
  264. "Warning: Dbversion %s does not meet nsslapd-idl-switch: \"old\"; "
  265. "nsslapd-idl-switch is updated to \"new\"\n",
  266. ldbmversion, 0, 0);
  267. }
  268. }
  269. else if ((0 == strcmp(ldbmversion, LDBM_VERSION_OLD)) ||
  270. (0 == PL_strcmp(ldbmversion, LDBM_VERSION_61)) ||
  271. (0 == PL_strcmp(ldbmversion, LDBM_VERSION_62)) ||
  272. (0 == strcmp(ldbmversion, LDBM_VERSION_60))) /* db: old */
  273. {
  274. if (idl_get_idl_new()) /* config: new */
  275. {
  276. replace_ldbm_config_value(CONFIG_IDL_SWITCH, "old", li);
  277. LDAPDebug(LDAP_DEBUG_ANY,
  278. "Warning: Dbversion %s does not meet nsslapd-idl-switch: \"new\"; "
  279. "nsslapd-idl-switch is updated to \"old\"\n",
  280. ldbmversion, 0, 0);
  281. }
  282. }
  283. else
  284. {
  285. LDAPDebug(LDAP_DEBUG_ANY,
  286. "Warning: Dbversion %s is not supported\n",
  287. ldbmversion, 0, 0);
  288. rval = 1;
  289. }
  290. /* ldbminfo is a common resource; should clean up when the job is done */
  291. li->li_flags &= ~LI_FORCE_MOD_CONFIG;
  292. return rval;
  293. }
  294. /* Do the work to upgrade a database if needed */
  295. /* When we're called, the database files have been opened, and any
  296. recovery needed has been performed. */
  297. int ldbm_upgrade(ldbm_instance *inst, int action)
  298. {
  299. int rval = 0;
  300. if (0 == action)
  301. {
  302. return rval;
  303. }
  304. if (action & DBVERSION_UPGRADE_3_4) /* upgrade from db3 to db4 */
  305. {
  306. /* basically, db4 supports db3.
  307. * so, what we need to do is rename XXX.db3 to XXX.db4 */
  308. int rval = dblayer_update_db_ext(inst, LDBM_SUFFIX_OLD, LDBM_SUFFIX);
  309. if (0 == rval)
  310. {
  311. if (idl_get_idl_new())
  312. {
  313. LDAPDebug(LDAP_DEBUG_ANY,
  314. "ldbm_upgrade: Upgrading instance %s to %s%s is successfully done.\n",
  315. inst->inst_name, LDBM_VERSION_BASE, PACKAGE_VERSION);
  316. }
  317. else
  318. {
  319. LDAPDebug(LDAP_DEBUG_ANY,
  320. "ldbm_upgrade: Upgrading instance %s to %s%s is successfully done.\n",
  321. inst->inst_name, LDBM_VERSION_OLD, 0);
  322. }
  323. }
  324. else
  325. {
  326. /* recovery effort ... */
  327. dblayer_update_db_ext(inst, LDBM_SUFFIX, LDBM_SUFFIX_OLD);
  328. return rval;
  329. }
  330. }
  331. return 0; /* Means that the database is new */
  332. }
  333. /* Here's the upgrade process :
  334. Delete all the keys from the parentid index
  335. Scan the id2entry file:
  336. Remove any hassubordinates attribute present
  337. Update the parentid index, maintaining a hash of high-count parents
  338. Scan the newly created parentid index updating the subordinatecount attributes.
  339. Most of the functionality is implemented in the import code.
  340. */
  341. #if 0
  342. static int upgrade_db_3x_40(backend *be)
  343. {
  344. struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
  345. int ret = 0;
  346. back_txn txn;
  347. static char* indexes_modified[] = {"parentid", "numsubordinates", NULL};
  348. LDAPDebug( LDAP_DEBUG_ANY, "WARNING: Detected a database older than this server, upgrading data...\n",0,0,0);
  349. dblayer_txn_init(li,&txn);
  350. ret = dblayer_txn_begin(li,NULL,&txn);
  351. if (0 != ret) {
  352. ldbm_nasty(filename,69,ret);
  353. goto error;
  354. }
  355. ret = indexfile_delete_all_keys(be,"parentid",&txn);
  356. if (0 != ret) {
  357. ldbm_nasty(filename,70,ret);
  358. goto error;
  359. }
  360. {
  361. Slapi_Mods smods;
  362. slapi_mods_init(&smods,1);
  363. /* Mods are to remove the hassubordinates attribute */
  364. slapi_mods_add(&smods, LDAP_MOD_DELETE, "hassubordinates", 0, NULL);
  365. /* This function takes care of generating the subordinatecount attribute and indexing it */
  366. ret = indexfile_primary_modifyall(be,slapi_mods_get_ldapmods_byref(&smods),indexes_modified,&txn);
  367. slapi_mods_done(&smods);
  368. }
  369. if (0 != ret) {
  370. ldbm_nasty(filename,61,ret);
  371. }
  372. error:
  373. if (0 != ret ) {
  374. dblayer_txn_abort(li,&txn);
  375. } else {
  376. ret = dblayer_txn_commit(li,&txn);
  377. if (0 != ret) {
  378. ldbm_nasty(filename,60,ret);
  379. } else {
  380. /* Now update DBVERSION file */
  381. }
  382. }
  383. if (0 == ret) {
  384. LDAPDebug( LDAP_DEBUG_ANY, "...upgrade complete.\n",0,0,0);
  385. } else {
  386. LDAPDebug( LDAP_DEBUG_ANY, "ERROR: Attempt to upgrade the older database FAILED.\n",0,0,0);
  387. }
  388. return ret;
  389. }
  390. #endif