repl_connext.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  3. * Copyright (C) 2005 Red Hat, Inc.
  4. * All rights reserved.
  5. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. #include <config.h>
  11. #endif
  12. /* repl_connext.c - replication extension to the Connection object
  13. */
  14. #include "repl5.h"
  15. /* ***** Supplier side ***** */
  16. /* NOT NEEDED YET */
  17. /* ***** Consumer side ***** */
  18. /* consumer connection extension constructor */
  19. void *
  20. consumer_connection_extension_constructor(void *object __attribute__((unused)), void *parent __attribute__((unused)))
  21. {
  22. consumer_connection_extension *ext = (consumer_connection_extension *)slapi_ch_malloc(sizeof(consumer_connection_extension));
  23. if (ext == NULL) {
  24. slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "consumer_connection_extension_constructor - "
  25. "Unable to create replication consumer connection extension - out of memory\n");
  26. } else {
  27. ext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
  28. ext->replica_acquired = NULL;
  29. ext->isreplicationsession = 0;
  30. ext->supplier_ruv = NULL;
  31. ext->connection = NULL;
  32. ext->in_use_opid = -1;
  33. ext->lock = PR_NewLock();
  34. if (NULL == ext->lock) {
  35. slapi_log_err(SLAPI_LOG_PLUGIN, repl_plugin_name, "consumer_connection_extension_constructor - "
  36. "Unable to create replication consumer connection extension lock - out of memory\n");
  37. /* no need to go through the full destructor, but still need to free up this memory */
  38. slapi_ch_free((void **)&ext);
  39. ext = NULL;
  40. }
  41. }
  42. return ext;
  43. }
  44. /* consumer connection extension destructor */
  45. void
  46. consumer_connection_extension_destructor(void *ext, void *object __attribute__((unused)), void *parent __attribute__((unused)))
  47. {
  48. PRUint64 connid = 0;
  49. if (ext) {
  50. /* Check to see if this replication session has acquired
  51. * a replica. If so, release it here.
  52. */
  53. consumer_connection_extension *connext = (consumer_connection_extension *)ext;
  54. if (replica_check_validity(connext->replica_acquired)) {
  55. Replica *r = connext->replica_acquired;
  56. /* If a total update was in progress, abort it */
  57. if (REPL_PROTOCOL_50_TOTALUPDATE == connext->repl_protocol_version) {
  58. Slapi_PBlock *pb = slapi_pblock_new();
  59. const Slapi_DN *repl_root_sdn = replica_get_root(r);
  60. PR_ASSERT(NULL != repl_root_sdn);
  61. if (NULL != repl_root_sdn) {
  62. slapi_pblock_set(pb, SLAPI_CONNECTION, connext->connection);
  63. slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void *)repl_root_sdn);
  64. slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
  65. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  66. "consumer_connection_extension_destructor - "
  67. "Aborting total update in progress for replicated "
  68. "area %s connid=%" PRIu64 "\n",
  69. slapi_sdn_get_dn(repl_root_sdn), connid);
  70. slapi_stop_bulk_import(pb);
  71. } else {
  72. slapi_log_err(SLAPI_LOG_ERR, repl_plugin_name,
  73. "consumer_connection_extension_destructor - Can't determine root "
  74. "of replicated area.\n");
  75. }
  76. slapi_pblock_destroy(pb);
  77. /* allow reaping again */
  78. replica_set_tombstone_reap_stop(r, PR_FALSE);
  79. }
  80. replica_relinquish_exclusive_access(r, connid, -1);
  81. connext->replica_acquired = NULL;
  82. }
  83. if (connext->supplier_ruv) {
  84. ruv_destroy((RUV **)&connext->supplier_ruv);
  85. }
  86. if (connext->lock) {
  87. PR_DestroyLock(connext->lock);
  88. connext->lock = NULL;
  89. }
  90. connext->in_use_opid = -1;
  91. connext->connection = NULL;
  92. slapi_ch_free((void **)&ext);
  93. }
  94. }
  95. /* Obtain exclusive access to this connection extension.
  96. * Returns the consumer_connection_extension* if successful, else NULL.
  97. *
  98. * This is similar to obtaining exclusive access to the replica, but not identical.
  99. * For the connection extension, you only want to hold on to exclusive access as
  100. * long as it is being actively used to process an operation. Mainly that means
  101. * while processing either a 'start' or an 'end' extended operation. This makes
  102. * certain that if another 'start' or 'end' operation is received on the connection,
  103. * the ops will not trample on each other's state. As soon as you are done with
  104. * that single operation, it is time to relinquish the connection extension.
  105. * That differs from acquiring exclusive access to the replica, which is held over
  106. * after the 'start' operation and relinquished during the 'end' operation.
  107. */
  108. consumer_connection_extension *
  109. consumer_connection_extension_acquire_exclusive_access(void *conn, PRUint64 connid, int opid)
  110. {
  111. consumer_connection_extension *ret = NULL;
  112. /* step 1, grab the connext */
  113. consumer_connection_extension *connext = (consumer_connection_extension *)
  114. repl_con_get_ext(REPL_CON_EXT_CONN, conn);
  115. if (NULL != connext) {
  116. /* step 2, acquire its lock */
  117. PR_Lock(connext->lock);
  118. /* step 3, see if it is not in use, or in use by us */
  119. if (0 > connext->in_use_opid) {
  120. /* step 4, take it! */
  121. connext->in_use_opid = opid;
  122. ret = connext;
  123. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  124. "consumer_connection_extension_acquire_exclusive_access - "
  125. "conn=%" PRIu64 " op=%d Acquired consumer connection extension\n",
  126. connid, opid);
  127. } else if (opid == connext->in_use_opid) {
  128. ret = connext;
  129. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  130. "consumer_connection_extension_acquire_exclusive_access - "
  131. "conn=%" PRIu64 " op=%d Reacquired consumer connection extension\n",
  132. connid, opid);
  133. } else {
  134. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  135. "consumer_connection_extension_acquire_exclusive_access - "
  136. "conn=%" PRIu64 " op=%d Could not acquire consumer connection extension; it is in use by op=%d\n",
  137. connid, opid, connext->in_use_opid);
  138. }
  139. /* step 5, drop the lock */
  140. PR_Unlock(connext->lock);
  141. } else {
  142. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  143. "consumer_connection_extension_acquire_exclusive_access - "
  144. "conn=%" PRIu64 " op=%d Could not acquire consumer extension, it is NULL!\n",
  145. connid, opid);
  146. }
  147. return ret;
  148. }
  149. /* Relinquish exclusive access to this connection extension.
  150. * Returns 0 if exclusive access could NOT be relinquished, and non-zero if it was.
  151. * Specifically:
  152. * 1 if the extension was in use and was relinquished.
  153. * 2 if the extension was not in use to begin with.
  154. *
  155. * The extension will only be relinquished if it was first acquired by this op,
  156. * or if 'force' is TRUE. Do not use 'force' without a legitimate reason, such
  157. * as when destroying the parent connection.
  158. *
  159. * cf. consumer_connection_extension_acquire_exclusive_access() for details on how,
  160. * when, and why you would want to acquire and relinquish exclusive access.
  161. */
  162. int
  163. consumer_connection_extension_relinquish_exclusive_access(void *conn, PRUint64 connid, int opid, PRBool force)
  164. {
  165. int ret = 0;
  166. /* step 1, grab the connext */
  167. consumer_connection_extension *connext = (consumer_connection_extension *)
  168. repl_con_get_ext(REPL_CON_EXT_CONN, conn);
  169. if (NULL != connext) {
  170. /* step 2, acquire its lock */
  171. PR_Lock(connext->lock);
  172. /* step 3, see if it is in use */
  173. if (0 > connext->in_use_opid) {
  174. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  175. "consumer_connection_extension_relinquish_exclusive_access - "
  176. "conn=%" PRIu64 " op=%d Consumer connection extension is not in use\n",
  177. connid, opid);
  178. ret = 2;
  179. } else if (opid == connext->in_use_opid) {
  180. /* step 4, relinquish it (normal) */
  181. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  182. "consumer_connection_extension_relinquish_exclusive_access - "
  183. "conn=%" PRIu64 " op=%d Relinquishing consumer connection extension\n",
  184. connid, opid);
  185. connext->in_use_opid = -1;
  186. ret = 1;
  187. } else if (force) {
  188. /* step 4, relinquish it (forced) */
  189. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  190. "consumer_connection_extension_relinquish_exclusive_access - "
  191. "conn=%" PRIu64 " op=%d Forced to relinquish consumer connection extension held by op=%d\n",
  192. connid, opid, connext->in_use_opid);
  193. connext->in_use_opid = -1;
  194. ret = 1;
  195. } else {
  196. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  197. "consumer_connection_extension_relinquish_exclusive_access - "
  198. "conn=%" PRIu64 " op=%d Not relinquishing consumer connection extension, it is held by op=%d!\n",
  199. connid, opid, connext->in_use_opid);
  200. }
  201. /* step 5, drop the lock */
  202. PR_Unlock(connext->lock);
  203. } else {
  204. slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name,
  205. "consumer_connection_extension_relinquish_exclusive_access - "
  206. "conn=%" PRIu64 " op=%d Could not relinquish consumer extension, it is NULL!\n",
  207. connid, opid);
  208. }
  209. return ret;
  210. }