retrocl_cn.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /** BEGIN COPYRIGHT BLOCK
  2. * Copyright 2001 Sun Microsystems, Inc.
  3. * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
  4. * All rights reserved.
  5. * END COPYRIGHT BLOCK **/
  6. #include "retrocl.h"
  7. static changeNumber retrocl_internal_cn = 0;
  8. static changeNumber retrocl_first_cn = 0;
  9. PRLock *retrocl_internal_lock = NULL;
  10. /*
  11. * Function: a2changeNumber
  12. *
  13. * Returns: changeNumber (long)
  14. *
  15. * Arguments: string
  16. *
  17. * Description: parses the string to a changenumber. changenumbers are
  18. * positive integers.
  19. *
  20. */
  21. static changeNumber a2changeNumber (const char *p)
  22. {
  23. changeNumber c;
  24. c = strntoul((char *)p,strlen(p),10);
  25. return c;
  26. }
  27. /*
  28. * Function: handle_cnum_entry
  29. * Arguments: op - pointer to Operation struct for this operation
  30. * e - pointer to returned entry.
  31. * Returns: nothing
  32. * Description: Search result handler for retrocl_getchangenum(). Sets the
  33. * op->o_handler_data to point to a structure which contains
  34. * the changenumber retrieved and an error code.
  35. */
  36. static int
  37. handle_cnum_entry( Slapi_Entry *e, void *callback_data )
  38. {
  39. cnumRet *cr = (cnumRet *)callback_data;
  40. Slapi_Value *sval=NULL;
  41. const struct berval *value;
  42. cr->cr_cnum = 0UL;
  43. cr->cr_time = NULL;
  44. if ( NULL != e ) {
  45. Slapi_Attr *chattr = NULL;
  46. sval = NULL;
  47. value = NULL;
  48. if ( slapi_entry_attr_find( e, attr_changenumber, &chattr ) == 0 ) {
  49. slapi_attr_first_value( chattr,&sval );
  50. if ( NULL != sval ) {
  51. value = slapi_value_get_berval ( sval );
  52. if( NULL != value && NULL != value->bv_val &&
  53. '\0' != value->bv_val[0]) {
  54. cr->cr_cnum = a2changeNumber( value->bv_val );
  55. }
  56. }
  57. }
  58. chattr = NULL;
  59. sval = NULL;
  60. value = NULL;
  61. chattr = NULL;
  62. sval = NULL;
  63. value = NULL;
  64. if ( slapi_entry_attr_find( e, attr_changetime, &chattr ) == 0 ) {
  65. slapi_attr_first_value( chattr,&sval );
  66. if ( NULL != sval) {
  67. value = slapi_value_get_berval ( sval );
  68. if (NULL != value && NULL != value->bv_val &&
  69. '\0' != value->bv_val[0]) {
  70. cr->cr_time = slapi_ch_strdup( value->bv_val );
  71. }
  72. }
  73. }
  74. }
  75. return 0;
  76. }
  77. /*
  78. * Function: handle_cnum_result
  79. * Arguments: err - error code returned from search
  80. * callback_data - private data for callback
  81. * Returns: nothing
  82. * Description: result handler for retrocl_getchangenum(). Sets the cr_lderr
  83. * field of the cnumRet struct to the error returned
  84. * from the backend.
  85. */
  86. static void
  87. handle_cnum_result( int err, void *callback_data )
  88. {
  89. cnumRet *cr = (cnumRet *)callback_data;
  90. cr->cr_lderr = err;
  91. }
  92. /*
  93. * Function: retrocl_get_changenumbers
  94. *
  95. * Returns: 0/-1
  96. *
  97. * Arguments: none
  98. *
  99. * Description: reads the first and last entry in the changelog to obtain
  100. * the starting and ending change numbers.
  101. *
  102. */
  103. int retrocl_get_changenumbers(void)
  104. {
  105. cnumRet cr;
  106. if (retrocl_internal_lock == NULL) {
  107. retrocl_internal_lock = PR_NewLock();
  108. if (retrocl_internal_lock == NULL) return -1;
  109. }
  110. if (retrocl_be_changelog == NULL) return -1;
  111. cr.cr_cnum = 0;
  112. cr.cr_time = 0;
  113. slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_FIRST,
  114. (char *)attr_changenumber, /* cast away const */
  115. NULL,NULL,0,&cr,NULL,handle_cnum_result,
  116. handle_cnum_entry, NULL);
  117. retrocl_first_cn = cr.cr_cnum;
  118. slapi_ch_free(( void **) &cr.cr_time );
  119. slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_LAST,
  120. (char *)attr_changenumber, /* cast away const */
  121. NULL,NULL,0,&cr,NULL,handle_cnum_result,
  122. handle_cnum_entry, NULL);
  123. retrocl_internal_cn = cr.cr_cnum;
  124. slapi_log_error(SLAPI_LOG_PLUGIN,"retrocl","Got changenumbers %d and %d\n",
  125. retrocl_first_cn,
  126. retrocl_internal_cn);
  127. slapi_ch_free(( void **) &cr.cr_time );
  128. return 0;
  129. }
  130. /*
  131. * Function: retrocl_getchangetime
  132. * Arguments: type - one of SLAPI_SEQ_FIRST, SLAPI_SEQ_LAST
  133. * Returns: The time of the requested change record. If the return value is
  134. * NO_TIME, the changelog could not be read.
  135. * If err is non-NULL, the memory it points to is set the the
  136. * error code returned from the backend. If "type" is not valid,
  137. * *err is set to -1.
  138. * Description: Get the first or last changenumber stored in the changelog,
  139. * depending on the value of argument "type".
  140. */
  141. time_t retrocl_getchangetime( int type, int *err )
  142. {
  143. cnumRet cr;
  144. time_t ret;
  145. if ( type != SLAPI_SEQ_FIRST && type != SLAPI_SEQ_LAST ) {
  146. if ( err != NULL ) {
  147. *err = -1;
  148. }
  149. return NO_TIME;
  150. }
  151. memset( &cr, '\0', sizeof( cnumRet ));
  152. slapi_seq_callback( RETROCL_CHANGELOG_DN, type,
  153. (char *)attr_changenumber, /* cast away const */
  154. NULL,
  155. NULL, 0, &cr, NULL,
  156. handle_cnum_result, handle_cnum_entry, NULL );
  157. if ( err != NULL ) {
  158. *err = cr.cr_lderr;
  159. }
  160. if ( NULL == cr.cr_time ) {
  161. ret = NO_TIME;
  162. } else {
  163. ret = parse_localTime( cr.cr_time );
  164. }
  165. slapi_ch_free(( void **) &cr.cr_time );
  166. return ret;
  167. }
  168. /*
  169. * Function: retrocl_forget_changenumbers
  170. *
  171. * Returns: none
  172. *
  173. * Arguments: none
  174. *
  175. * Description: used only when the server is shutting down
  176. *
  177. */
  178. void retrocl_forget_changenumbers(void)
  179. {
  180. if (retrocl_internal_lock == NULL) return;
  181. PR_Lock(retrocl_internal_lock);
  182. retrocl_first_cn = 0;
  183. retrocl_internal_cn = 0;
  184. PR_Unlock(retrocl_internal_lock);
  185. }
  186. /*
  187. * Function: retrocl_get_first_changenumber
  188. *
  189. * Returns: changeNumber
  190. *
  191. * Arguments: none
  192. *
  193. * Description: used in root DSE
  194. *
  195. */
  196. changeNumber retrocl_get_first_changenumber(void)
  197. {
  198. changeNumber cn;
  199. PR_Lock(retrocl_internal_lock);
  200. cn = retrocl_first_cn;
  201. PR_Unlock(retrocl_internal_lock);
  202. return cn;
  203. }
  204. /*
  205. * Function: retrocl_set_first_changenumber
  206. *
  207. * Returns: none
  208. *
  209. * Arguments: changenumber
  210. *
  211. * Description: used in changelog trimming
  212. *
  213. */
  214. void retrocl_set_first_changenumber(changeNumber cn)
  215. {
  216. PR_Lock(retrocl_internal_lock);
  217. retrocl_first_cn = cn;
  218. PR_Unlock(retrocl_internal_lock);
  219. }
  220. /*
  221. * Function: retrocl_get_last_changenumber
  222. *
  223. * Returns:
  224. *
  225. * Arguments:
  226. *
  227. * Description: used in root DSE
  228. *
  229. */
  230. changeNumber retrocl_get_last_changenumber(void)
  231. {
  232. changeNumber cn;
  233. PR_Lock(retrocl_internal_lock);
  234. cn = retrocl_internal_cn;
  235. PR_Unlock(retrocl_internal_lock);
  236. return cn;
  237. }
  238. /*
  239. * Function: retrocl_commit_changenumber
  240. *
  241. * Returns: none
  242. *
  243. * Arguments: none, lock must be held
  244. *
  245. * Description: NOTE! MUST BE PRECEEDED BY retrocl_assign_changenumber
  246. *
  247. */
  248. void retrocl_commit_changenumber(void)
  249. {
  250. if ( retrocl_first_cn == 0) {
  251. retrocl_first_cn = retrocl_internal_cn;
  252. }
  253. }
  254. /*
  255. * Function: retrocl_release_changenumber
  256. *
  257. * Returns: none
  258. *
  259. * Arguments: none, lock must be held
  260. *
  261. * Description: NOTE! MUST BE PRECEEDED BY retrocl_assign_changenumber
  262. *
  263. */
  264. void retrocl_release_changenumber(void)
  265. {
  266. retrocl_internal_cn--;
  267. }
  268. /*
  269. * Function: retrocl_update_lastchangenumber
  270. *
  271. * Returns: 0/-1
  272. *
  273. * Arguments: none
  274. *
  275. * Description: reads the last entry in the changelog to obtain
  276. * the last change number.
  277. *
  278. */
  279. int retrocl_update_lastchangenumber(void)
  280. {
  281. cnumRet cr;
  282. if (retrocl_internal_lock == NULL) {
  283. retrocl_internal_lock = PR_NewLock();
  284. if (retrocl_internal_lock == NULL) return -1;
  285. }
  286. if (retrocl_be_changelog == NULL) return -1;
  287. cr.cr_cnum = 0;
  288. cr.cr_time = 0;
  289. slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_LAST,
  290. (char *)attr_changenumber, /* cast away const */
  291. NULL,NULL,0,&cr,NULL,handle_cnum_result,
  292. handle_cnum_entry, NULL);
  293. retrocl_internal_cn = cr.cr_cnum;
  294. slapi_log_error(SLAPI_LOG_PLUGIN,"retrocl","Refetched last changenumber = %d \n",
  295. retrocl_internal_cn);
  296. slapi_ch_free(( void **) &cr.cr_time );
  297. return 0;
  298. }
  299. /*
  300. * Function: retrocl_assign_changenumber
  301. *
  302. * Returns: change number, 0 on error
  303. *
  304. * Arguments: none. Lock must be held.
  305. *
  306. * Description: NOTE! MUST BE FOLLOWED BY retrocl_commit_changenumber or
  307. * retrocl_release_changenumber
  308. *
  309. */
  310. changeNumber retrocl_assign_changenumber(void)
  311. {
  312. changeNumber cn;
  313. if (retrocl_internal_lock == NULL) return 0;
  314. /* Before we assign the changenumber; we should check for the
  315. * validity of the internal assignment of retrocl_internal_cn
  316. * we had from the startup */
  317. if(retrocl_internal_cn <= retrocl_first_cn){
  318. /* the numbers have become out of sync - retrocl_get_changenumbers
  319. * gets called only once during startup and it may have had a problem
  320. * getting the last changenumber.
  321. * If there was any problem then update the lastchangenumber from the changelog db.
  322. * This function is being called by only the thread that is actually writing
  323. * to the changelog.
  324. */
  325. retrocl_update_lastchangenumber();
  326. }
  327. retrocl_internal_cn++;
  328. cn = retrocl_internal_cn;
  329. return cn;
  330. }