usn_cleanup.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  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) 2009 Red Hat, Inc.
  35. * All rights reserved.
  36. * END COPYRIGHT BLOCK **/
  37. #ifdef HAVE_CONFIG_H
  38. # include <config.h>
  39. #endif
  40. #include "usn.h"
  41. struct usn_cleanup_data {
  42. char *suffix;
  43. char *maxusn_to_delete;
  44. };
  45. static int usn_cleanup_add(Slapi_PBlock *pb, Slapi_Entry *e,
  46. Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
  47. int
  48. usn_cleanup_start(Slapi_PBlock *pb)
  49. {
  50. int rc = slapi_task_register_handler("USN tombstone cleanup task",
  51. usn_cleanup_add);
  52. return rc;
  53. }
  54. /*
  55. * Task thread
  56. */
  57. static void
  58. usn_cleanup_thread(void *arg)
  59. {
  60. Slapi_Task *task = (Slapi_Task *)arg;
  61. int rv = 0;
  62. int total_work = 2;
  63. /* fetch our argument from the task */
  64. struct usn_cleanup_data *cleanup_data =
  65. (struct usn_cleanup_data*)slapi_task_get_data(task);
  66. Slapi_PBlock *search_pb = NULL;
  67. Slapi_Entry **entries = NULL, **ep = NULL;
  68. Slapi_PBlock *delete_pb = NULL;
  69. char *filter = "objectclass=nsTombstone";
  70. slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
  71. "--> usn_cleanup_thread\n");
  72. if (NULL == usn_get_identity()) { /* plugin is not initialized */
  73. slapi_task_log_notice(task, "USN plugin is not initialized\n");
  74. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  75. "USN tombstone cleanup: USN plugin is not initialized\n");
  76. rv = -1;
  77. filter = NULL; /* so we don't try to free it */
  78. goto bail;
  79. }
  80. /* update task state to show it's running */
  81. slapi_task_begin(task, total_work);
  82. if (cleanup_data->maxusn_to_delete) {
  83. /* (&(objectclass=nsTombstone)(entryusn<=maxusn_to_delete)) */
  84. int filter_len =
  85. strlen(filter) + strlen(cleanup_data->maxusn_to_delete) + 32;
  86. filter = (char *)slapi_ch_malloc(filter_len);
  87. PR_snprintf(filter, filter_len,
  88. "(&(objectclass=nsTombstone)(entryusn<=%s))",
  89. cleanup_data->maxusn_to_delete);
  90. }
  91. search_pb = slapi_pblock_new();
  92. slapi_search_internal_set_pb(search_pb, cleanup_data->suffix,
  93. LDAP_SCOPE_SUBTREE, filter,
  94. NULL, 0, NULL, NULL, usn_get_identity(), 0);
  95. slapi_search_internal_pb(search_pb);
  96. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rv);
  97. if (LDAP_NO_SUCH_OBJECT == rv) {
  98. slapi_task_log_notice(task,
  99. "USN tombstone cleanup: no such suffix %s.\n",
  100. cleanup_data->suffix);
  101. slapi_task_log_status(task,
  102. "USN tombstone cleanup: no such suffix %s.\n",
  103. cleanup_data->suffix);
  104. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  105. "USN tombstone cleanup: no such suffix %s.\n",
  106. cleanup_data->suffix);
  107. goto bail;
  108. } else if (LDAP_SUCCESS != rv) {
  109. slapi_task_log_notice(task,
  110. "USN tombstone cleanup: searching tombstone entries "
  111. "in %s failed; (%d).\n", cleanup_data->suffix, rv);
  112. slapi_task_log_status(task,
  113. "USN tombstone cleanup: searching tombstone entries in "
  114. "%s failed; (%d).\n", cleanup_data->suffix, rv);
  115. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  116. "USN tombstone cleanup: searching tombstone entries in "
  117. "%s failed; (%d).\n", cleanup_data->suffix, rv);
  118. goto bail;
  119. }
  120. slapi_task_log_notice(task,
  121. "USN tombstone cleanup task starts (suffix: %s) ...\n",
  122. cleanup_data->suffix);
  123. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  124. "USN tombstone cleanup task starts (suffix: %s) ...\n",
  125. cleanup_data->suffix);
  126. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  127. delete_pb = slapi_pblock_new();
  128. for (ep = entries; ep && *ep; ep++) {
  129. int delrv = 0;
  130. const Slapi_DN *sdn = slapi_entry_get_sdn_const(*ep);
  131. slapi_delete_internal_set_pb(delete_pb, slapi_sdn_get_dn(sdn),
  132. NULL, NULL, usn_get_identity(), 0);
  133. slapi_delete_internal_pb(delete_pb);
  134. slapi_pblock_get(delete_pb, SLAPI_PLUGIN_INTOP_RESULT, &delrv);
  135. if (LDAP_SUCCESS != delrv) {
  136. slapi_task_log_notice(task,
  137. "USN tombstone cleanup: deleting %s failed; (%d).\n",
  138. slapi_sdn_get_dn(sdn), delrv);
  139. slapi_task_log_status(task,
  140. "USN tombstone cleanup: deleting %s failed; (%d).\n",
  141. slapi_sdn_get_dn(sdn), delrv);
  142. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  143. "USN tombstone cleanup: deleting %s failed; (%d).\n",
  144. slapi_sdn_get_dn(sdn), delrv);
  145. rv = delrv;
  146. }
  147. slapi_pblock_init(delete_pb);
  148. slapi_task_inc_progress(task);
  149. }
  150. slapi_task_log_notice(task, "USN tombstone cleanup task finished.");
  151. slapi_task_log_status(task, "USN tombstone cleanup task finished.");
  152. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  153. "USN tombstone cleanup task finished.\n");
  154. bail:
  155. slapi_free_search_results_internal(search_pb);
  156. slapi_pblock_destroy(search_pb);
  157. slapi_pblock_destroy(delete_pb);
  158. if (cleanup_data->maxusn_to_delete) {
  159. slapi_ch_free_string(&filter);
  160. }
  161. slapi_ch_free_string(&cleanup_data->maxusn_to_delete);
  162. slapi_ch_free_string(&cleanup_data->suffix);
  163. slapi_ch_free((void **)&cleanup_data);
  164. /* this will queue the destruction of the task */
  165. slapi_task_finish(task, rv);
  166. slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
  167. "<-- usn_cleanup_thread\n");
  168. }
  169. #define MAPPING_TREE_BASE_DN "cn=mapping tree,cn=config"
  170. static int
  171. _usn_cleanup_is_mmr_enabled(const char *suffix)
  172. {
  173. Slapi_PBlock *search_pb = NULL;
  174. Slapi_Entry **entries = NULL;
  175. char *base_dn = NULL;
  176. int rc = 0; /* disabled, by default */
  177. /* This function converts the old style DN to the new one */
  178. base_dn = slapi_create_dn_string("cn=replica,cn=\"%s\",%s",
  179. suffix, MAPPING_TREE_BASE_DN);
  180. if (NULL == base_dn) {
  181. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  182. "_usn_cleanup_is_mmr_enabled: failed to normalize "
  183. "mappingtree dn for %s\n", suffix);
  184. return 1;
  185. }
  186. search_pb = slapi_pblock_new();
  187. slapi_search_internal_set_pb(search_pb, base_dn, LDAP_SCOPE_ONELEVEL,
  188. "objectclass=nsDS5ReplicationAgreement",
  189. NULL, 0, NULL, NULL, usn_get_identity(), 0);
  190. slapi_search_internal_pb(search_pb);
  191. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
  192. if (LDAP_SUCCESS != rc) { /* agreement is not available */
  193. goto bail;
  194. }
  195. slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
  196. if (entries && *entries) {
  197. rc = 1; /* At least one agreement on the suffix is found */
  198. }
  199. bail:
  200. slapi_free_search_results_internal(search_pb);
  201. slapi_pblock_destroy(search_pb);
  202. slapi_ch_free_string(&base_dn);
  203. return rc;
  204. }
  205. static int
  206. usn_cleanup_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
  207. int *returncode, char *returntext, void *arg)
  208. {
  209. PRThread *thread = NULL;
  210. char *cn = NULL;
  211. char *suffix = NULL;
  212. char *backend = NULL;
  213. char *maxusn = NULL;
  214. struct usn_cleanup_data *cleanup_data = NULL;
  215. int rv = SLAPI_DSE_CALLBACK_OK;
  216. Slapi_Task *task = NULL;
  217. Slapi_Backend *be = NULL;
  218. const Slapi_DN *be_suffix = NULL;
  219. slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
  220. "--> usn_cleanup_add\n");
  221. *returncode = LDAP_SUCCESS;
  222. cn = slapi_entry_attr_get_charptr(e, "cn");
  223. if (NULL == cn) {
  224. *returncode = LDAP_OBJECT_CLASS_VIOLATION;
  225. rv = SLAPI_DSE_CALLBACK_ERROR;
  226. goto bail;
  227. }
  228. /* get args */
  229. suffix = slapi_entry_attr_get_charptr(e, "suffix");
  230. backend = slapi_entry_attr_get_charptr(e, "backend");
  231. maxusn = slapi_entry_attr_get_charptr(e, "maxusn_to_delete");
  232. if (NULL == suffix && NULL == backend) {
  233. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  234. "USN tombstone cleanup: Both suffix and backend are missing.\n");
  235. *returncode = LDAP_PARAM_ERROR;
  236. rv = SLAPI_DSE_CALLBACK_ERROR;
  237. goto bail;
  238. }
  239. /* suffix is not given, but backend is; get the suffix */
  240. if (NULL == suffix && NULL != backend) {
  241. be = slapi_be_select_by_instance_name(backend);
  242. be_suffix = slapi_be_getsuffix(be, 0);
  243. if (be_suffix) {
  244. suffix = slapi_ch_strdup(slapi_sdn_get_ndn(be_suffix));
  245. } else {
  246. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  247. "USN tombstone cleanup: Backend %s is invalid.\n", backend);
  248. *returncode = LDAP_PARAM_ERROR;
  249. rv = SLAPI_DSE_CALLBACK_ERROR;
  250. goto bail;
  251. }
  252. }
  253. /* The suffix is the target of replication,
  254. * we don't want to clean up tombstones used by MMR */
  255. if (_usn_cleanup_is_mmr_enabled(suffix)) {
  256. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  257. "USN tombstone cleanup: Suffix %s is replicated. Unwilling to "
  258. "perform cleaning up tombstones.\n", suffix);
  259. *returncode = LDAP_UNWILLING_TO_PERFORM;
  260. rv = SLAPI_DSE_CALLBACK_ERROR;
  261. goto bail;
  262. }
  263. cleanup_data =
  264. (struct usn_cleanup_data *)slapi_ch_malloc(sizeof(struct usn_cleanup_data));
  265. cleanup_data->suffix = slapi_ch_strdup(suffix);
  266. cleanup_data->maxusn_to_delete = slapi_ch_strdup(maxusn);
  267. /* allocate new task now */
  268. task = slapi_new_task(slapi_entry_get_ndn(e));
  269. if (task == NULL) {
  270. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  271. "USN tombstone cleanup: unable to allocate new task.\n");
  272. *returncode = LDAP_OPERATIONS_ERROR;
  273. rv = SLAPI_DSE_CALLBACK_ERROR;
  274. slapi_ch_free((void**)&cleanup_data);
  275. goto bail;
  276. }
  277. /* Stash our argument in the task for use by the task thread */
  278. slapi_task_set_data(task, cleanup_data);
  279. /* start the USN tombstone cleanup task as a separate thread */
  280. thread = PR_CreateThread(PR_USER_THREAD, usn_cleanup_thread,
  281. (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
  282. PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
  283. if (thread == NULL) {
  284. slapi_log_error(SLAPI_LOG_FATAL, USN_PLUGIN_SUBSYSTEM,
  285. "USN tombstone cleanup: unable to create task thread.\n");
  286. *returncode = LDAP_OPERATIONS_ERROR;
  287. rv = SLAPI_DSE_CALLBACK_ERROR;
  288. slapi_task_finish(task, *returncode);
  289. } else {
  290. /* thread successful */
  291. rv = SLAPI_DSE_CALLBACK_OK;
  292. }
  293. bail:
  294. slapi_ch_free_string(&cn);
  295. slapi_ch_free_string(&suffix);
  296. slapi_ch_free_string(&backend);
  297. slapi_ch_free_string(&maxusn);
  298. slapi_log_error(SLAPI_LOG_TRACE, USN_PLUGIN_SUBSYSTEM,
  299. "<-- usn_cleanup_add\n");
  300. return rv;
  301. }