csn.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415
  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. /*
  39. * csn.c - CSN
  40. */
  41. #include <string.h>
  42. #include "slap.h"
  43. #include <prcountr.h>
  44. #define _CSN_TSTAMP_STRSIZE_STR "8"
  45. #define _CSN_SEQNUM_STRSIZE_STR "4"
  46. #define _CSN_REPLID_STRSIZE_STR "4"
  47. #define _CSN_SUBSEQNUM_STRSIZE_STR "4"
  48. #define _CSN_TSTAMP_SCANSTR "%"_CSN_TSTAMP_STRSIZE_STR"lx"
  49. #define _CSN_SEQNUM_SCANSTR "%"_CSN_SEQNUM_STRSIZE_STR"hx"
  50. #define _CSN_REPLID_SCANSTR "%"_CSN_REPLID_STRSIZE_STR"hx"
  51. #define _CSN_SUBSEQNUM_SCANSTR "%"_CSN_SUBSEQNUM_STRSIZE_STR"hx"
  52. #define _CSN_TSORDER_SPRINTSTR "%08x%04x%04x%04x"
  53. #define _CSN_TSORDER_TSTAMP_OFFSET 0
  54. #define _CSN_TSORDER_SEQNUM_OFFSET 8
  55. #define _CSN_TSORDER_REPLID_OFFSET 12
  56. #define _CSN_TSORDER_SUBSEQNUM_OFFSET 16
  57. static PRBool _csnIsValidString(const char *csnStr);
  58. /*
  59. * Debugging counters.
  60. */
  61. static int counters_created= 0;
  62. PR_DEFINE_COUNTER(slapi_csn_counter_created);
  63. PR_DEFINE_COUNTER(slapi_csn_counter_deleted);
  64. PR_DEFINE_COUNTER(slapi_csn_counter_exist);
  65. /*
  66. * **************************************************************************
  67. * CSN Functions
  68. * **************************************************************************
  69. */
  70. static void
  71. csn_create_counters()
  72. {
  73. PR_CREATE_COUNTER(slapi_csn_counter_created,"Slapi_CSN","created","");
  74. PR_CREATE_COUNTER(slapi_csn_counter_deleted,"Slapi_CSN","deleted","");
  75. PR_CREATE_COUNTER(slapi_csn_counter_exist,"Slapi_CSN","exist","");
  76. counters_created= 1;
  77. }
  78. CSN *csn_new()
  79. {
  80. if(!counters_created)
  81. {
  82. csn_create_counters();
  83. }
  84. PR_INCREMENT_COUNTER(slapi_csn_counter_created);
  85. PR_INCREMENT_COUNTER(slapi_csn_counter_exist);
  86. return (CSN*)slapi_ch_calloc(sizeof(CSN),1);
  87. }
  88. CSN *csn_new_by_string(const char *s)
  89. {
  90. CSN *newcsn= NULL;
  91. if(s!=NULL)
  92. {
  93. if(_csnIsValidString(s))
  94. {
  95. newcsn= csn_new();
  96. csn_init_by_string(newcsn,s);
  97. }
  98. }
  99. return newcsn;
  100. }
  101. void csn_init(CSN *csn)
  102. {
  103. if(csn!=NULL)
  104. {
  105. memset(csn,0,sizeof(CSN));
  106. }
  107. }
  108. void csn_init_by_csn(CSN *csn1,const CSN *csn2)
  109. {
  110. if(csn2!=NULL)
  111. {
  112. memcpy(csn1,csn2,sizeof(CSN));
  113. }
  114. else
  115. {
  116. csn_init(csn1);
  117. }
  118. }
  119. void csn_init_by_string(CSN *csn, const char *s)
  120. {
  121. time_t csnTime= 0;
  122. PRUint16 csnSeqNum= 0;
  123. ReplicaId rid= 0;
  124. PRUint16 csnSubSeqNum= 0;
  125. if(_csnIsValidString(s))
  126. {
  127. /* JCM - char2hex faster */
  128. sscanf((s+_CSN_TSORDER_TSTAMP_OFFSET), _CSN_TSTAMP_SCANSTR, &csnTime); /* JCM - scanf is very slow */
  129. sscanf((s+_CSN_TSORDER_SEQNUM_OFFSET), _CSN_SEQNUM_SCANSTR, &csnSeqNum);/* JCM - scanf is very slow */
  130. sscanf((s+_CSN_TSORDER_REPLID_OFFSET), _CSN_REPLID_SCANSTR, &rid);/* JCM - scanf is very slow */
  131. sscanf((s+_CSN_TSORDER_SUBSEQNUM_OFFSET), _CSN_SUBSEQNUM_SCANSTR, &csnSubSeqNum);/* JCM - scanf is very slow */
  132. csn->tstamp= csnTime;
  133. csn->seqnum= csnSeqNum;
  134. csn->rid= rid;
  135. csn->subseqnum= csnSubSeqNum;
  136. }
  137. }
  138. CSN *csn_dup(const CSN *csn)
  139. {
  140. CSN *newcsn= NULL;
  141. if(csn!=NULL)
  142. {
  143. newcsn= csn_new();
  144. csn_init_by_csn(newcsn,csn);
  145. }
  146. return newcsn;
  147. }
  148. void csn_done(CSN *csn)
  149. {
  150. }
  151. void csn_free(CSN **csn)
  152. {
  153. if(csn!=NULL && *csn!=NULL)
  154. {
  155. if(!counters_created)
  156. {
  157. csn_create_counters();
  158. }
  159. PR_INCREMENT_COUNTER(slapi_csn_counter_deleted);
  160. PR_DECREMENT_COUNTER(slapi_csn_counter_exist);
  161. slapi_ch_free((void **)csn);
  162. }
  163. return;
  164. }
  165. void csn_set_replicaid(CSN *csn, ReplicaId rid)
  166. {
  167. csn->rid= rid;
  168. }
  169. void csn_set_time(CSN *csn, time_t csntime)
  170. {
  171. csn->tstamp= csntime;
  172. }
  173. void csn_set_seqnum(CSN *csn, PRUint16 seqnum)
  174. {
  175. csn->seqnum= seqnum;
  176. }
  177. ReplicaId csn_get_replicaid(const CSN *csn)
  178. {
  179. return csn->rid;
  180. }
  181. PRUint16 csn_get_seqnum(const CSN *csn)
  182. {
  183. return csn->seqnum;
  184. }
  185. time_t csn_get_time(const CSN *csn)
  186. {
  187. if(csn==NULL)
  188. {
  189. return 0;
  190. }
  191. else
  192. {
  193. return csn->tstamp;
  194. }
  195. }
  196. /*
  197. * WARNING: ss must point to memory at least CSN_STRSIZE bytes long,
  198. * WARNING: or be NULL, which means this function will allocate the
  199. * WARNING: memory, which must be free'd by the caller.
  200. */
  201. char *
  202. csn_as_string(const CSN *csn, PRBool replicaIdOrder, char *ss)
  203. {
  204. char *s= ss;
  205. if(s==NULL)
  206. {
  207. s= slapi_ch_malloc(CSN_STRSIZE);
  208. }
  209. if(csn==NULL)
  210. {
  211. s[0]= '\0';
  212. }
  213. else
  214. {
  215. /* JCM - hex2char would be quicker */
  216. sprintf(s,"%08lx%04x%04x%04x",
  217. csn->tstamp,csn->seqnum,csn->rid, csn->subseqnum);
  218. }
  219. return s;
  220. }
  221. /*
  222. * WARNING: ss must point to memory at least (7+CSN_STRSIZE) bytes long,
  223. * WARNING: or be NULL, which means this function will allocate the
  224. * WARNING: memory, which must be free'd by the caller.
  225. */
  226. char *
  227. csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss)
  228. {
  229. char *s= ss;
  230. if(csn!=NULL)
  231. {
  232. if(s==NULL)
  233. {
  234. s= slapi_ch_malloc(8+CSN_STRSIZE);
  235. }
  236. s[0]= ';';
  237. switch(t)
  238. {
  239. case CSN_TYPE_UNKNOWN:
  240. s[1]= 'x';
  241. s[2]= '1';
  242. break;
  243. case CSN_TYPE_NONE:
  244. s[1]= 'x';
  245. s[2]= '2';
  246. break;
  247. case CSN_TYPE_ATTRIBUTE_DELETED:
  248. s[1]= 'a';
  249. s[2]= 'd';
  250. break;
  251. case CSN_TYPE_VALUE_UPDATED:
  252. s[1]= 'v';
  253. s[2]= 'u';
  254. break;
  255. case CSN_TYPE_VALUE_DELETED:
  256. s[1]= 'v';
  257. s[2]= 'd';
  258. break;
  259. case CSN_TYPE_VALUE_DISTINGUISHED:
  260. s[1]= 'm';
  261. s[2]= 'd';
  262. break;
  263. }
  264. s[3]= 'c';
  265. s[4]= 's';
  266. s[5]= 'n';
  267. s[6]= '-';
  268. csn_as_string(csn,PR_FALSE,s+7);
  269. }
  270. return s;
  271. }
  272. int
  273. csn_compare(const CSN *csn1, const CSN *csn2)
  274. {
  275. PRInt32 retVal;
  276. if(csn1!=NULL && csn2!=NULL)
  277. {
  278. /* csns can't be compared via memcmp (previuos version of the code)
  279. because, on NT, bytes are reversed */
  280. if (csn1->tstamp < csn2->tstamp)
  281. retVal = -1;
  282. else if (csn1->tstamp > csn2->tstamp)
  283. retVal = 1;
  284. else
  285. {
  286. if (csn1->seqnum < csn2->seqnum)
  287. retVal = -1;
  288. else if (csn1->seqnum > csn2->seqnum)
  289. retVal = 1;
  290. else
  291. {
  292. if (csn1->rid < csn2->rid)
  293. retVal = -1;
  294. else if (csn1->rid > csn2->rid)
  295. retVal = 1;
  296. else
  297. {
  298. if (csn1->subseqnum < csn2->subseqnum)
  299. retVal = -1;
  300. else if (csn1->subseqnum > csn2->subseqnum)
  301. retVal = 1;
  302. else
  303. retVal = 0;
  304. }
  305. }
  306. }
  307. }
  308. else if(csn1!=NULL && csn2==NULL)
  309. {
  310. retVal= 1; /* csn1>csn2 */
  311. }
  312. else if (csn1==NULL && csn2!=NULL)
  313. {
  314. retVal= -1; /* csn1<csn2 */
  315. }
  316. else /* (csn1==NULL && csn2==NULL) */
  317. {
  318. retVal= 0; /* The same */
  319. }
  320. return(retVal);
  321. }
  322. time_t csn_time_difference(const CSN *csn1, const CSN *csn2)
  323. {
  324. return csn_get_time(csn1) - csn_get_time(csn2);
  325. }
  326. const CSN *
  327. csn_max(const CSN *csn1,const CSN *csn2)
  328. {
  329. if(csn_compare(csn1, csn2)>0)
  330. {
  331. return csn1;
  332. }
  333. else
  334. {
  335. return csn2;
  336. }
  337. }
  338. int csn_increment_subsequence (CSN *csn)
  339. {
  340. if (csn == NULL)
  341. {
  342. return -1;
  343. }
  344. else if (csn->subseqnum == 0xFFFFFFFF)
  345. {
  346. slapi_log_error(SLAPI_LOG_FATAL, NULL,
  347. "csn_increment_subsequence: subsequence overflow\n");
  348. return -1;
  349. }
  350. else
  351. {
  352. csn->subseqnum ++;
  353. return 0;
  354. }
  355. }
  356. /*
  357. * sizeof(vucsn-011111111222233334444)
  358. * Does not include the trailing '\0'
  359. */
  360. size_t
  361. csn_string_size()
  362. {
  363. return LDIF_CSNPREFIX_MAXLENGTH + _CSN_VALIDCSN_STRLEN;
  364. }
  365. static PRBool
  366. _csnIsValidString(const char *s)
  367. {
  368. if(NULL == s) {
  369. return(PR_FALSE);
  370. }
  371. if(strlen(s) < _CSN_VALIDCSN_STRLEN) {
  372. return(PR_FALSE);
  373. }
  374. /* some more checks on validity of tstamp portion? */
  375. return(PR_TRUE);
  376. }