Development of an internal social media platform with personalised dashboards for students
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

MergeTemplate.c 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. /*****************************************************************************
  2. Copyright (c) 2001, 2002 Zope Foundation and Contributors.
  3. All Rights Reserved.
  4. This software is subject to the provisions of the Zope Public License,
  5. Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
  6. THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
  7. WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  8. WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
  9. FOR A PARTICULAR PURPOSE
  10. ****************************************************************************/
  11. #define MERGETEMPLATE_C "$Id$\n"
  12. /****************************************************************************
  13. Set operations
  14. ****************************************************************************/
  15. static int
  16. merge_output(Bucket *r, SetIteration *i, int mapping)
  17. {
  18. if (r->len >= r->size && Bucket_grow(r, -1, !mapping) < 0)
  19. return -1;
  20. COPY_KEY(r->keys[r->len], i->key);
  21. INCREF_KEY(r->keys[r->len]);
  22. if (mapping) {
  23. COPY_VALUE(r->values[r->len], i->value);
  24. INCREF_VALUE(r->values[r->len]);
  25. }
  26. r->len++;
  27. return 0;
  28. }
  29. /* The "reason" argument is a little integer giving "a reason" for the
  30. * error. In the Zope3 codebase, these are mapped to explanatory strings
  31. * via zodb/btrees/interfaces.py.
  32. */
  33. static PyObject *
  34. merge_error(int p1, int p2, int p3, int reason)
  35. {
  36. PyObject *r;
  37. UNLESS (r=Py_BuildValue("iiii", p1, p2, p3, reason)) r=Py_None;
  38. if (ConflictError == NULL) {
  39. ConflictError = PyExc_ValueError;
  40. Py_INCREF(ConflictError);
  41. }
  42. PyErr_SetObject(ConflictError, r);
  43. if (r != Py_None)
  44. {
  45. Py_DECREF(r);
  46. }
  47. return NULL;
  48. }
  49. /* It's hard to explain "the rules" for bucket_merge, in large part because
  50. * any automatic conflict-resolution scheme is going to be incorrect for
  51. * some endcases of *some* app. The scheme here is pretty conservative,
  52. * and should be OK for most apps. It's easier to explain what the code
  53. * allows than what it forbids:
  54. *
  55. * Leaving things alone: it's OK if both s2 and s3 leave a piece of s1
  56. * alone (don't delete the key, and don't change the value).
  57. *
  58. * Key deletion: a transaction (s2 or s3) can delete a key (from s1), but
  59. * only if the other transaction (of s2 and s3) doesn't delete the same key.
  60. * However, it's not OK for s2 and s3 to, between them, end up deleting all
  61. * the keys. This is a higher-level constraint, due to that the caller of
  62. * bucket_merge() doesn't have enough info to unlink the resulting empty
  63. * bucket from its BTree correctly. It's also not OK if s2 or s3 are empty,
  64. * because the transaction that emptied the bucket unlinked the bucket from
  65. * the tree, and nothing we do here can get it linked back in again.
  66. *
  67. * Key insertion: s2 or s3 can add a new key, provided the other transaction
  68. * doesn't insert the same key. It's not OK even if they insert the same
  69. * <key, value> pair.
  70. *
  71. * Mapping value modification: s2 or s3 can modify the value associated
  72. * with a key in s1, provided the other transaction doesn't make a
  73. * modification of the same key to a different value. It's OK if s2 and s3
  74. * both give the same new value to the key while it's hard to be precise about
  75. * why, this doesn't seem consistent with that it's *not* OK for both to add
  76. * a new key mapping to the same value).
  77. */
  78. static PyObject *
  79. bucket_merge(Bucket *s1, Bucket *s2, Bucket *s3)
  80. {
  81. Bucket *r=0;
  82. PyObject *s;
  83. SetIteration i1 = {0,0,0}, i2 = {0,0,0}, i3 = {0,0,0};
  84. int cmp12, cmp13, cmp23, mapping, set;
  85. /* If either "after" bucket is empty, punt. */
  86. if (s2->len == 0 || s3->len == 0)
  87. {
  88. merge_error(-1, -1, -1, 12);
  89. goto err;
  90. }
  91. if (initSetIteration(&i1, OBJECT(s1), 1) < 0)
  92. goto err;
  93. if (initSetIteration(&i2, OBJECT(s2), 1) < 0)
  94. goto err;
  95. if (initSetIteration(&i3, OBJECT(s3), 1) < 0)
  96. goto err;
  97. mapping = i1.usesValue | i2.usesValue | i3.usesValue;
  98. set = !mapping;
  99. if (mapping)
  100. r = (Bucket *)PyObject_CallObject((PyObject *)&BucketType, NULL);
  101. else
  102. r = (Bucket *)PyObject_CallObject((PyObject *)&SetType, NULL);
  103. if (r == NULL)
  104. goto err;
  105. if (i1.next(&i1) < 0)
  106. goto err;
  107. if (i2.next(&i2) < 0)
  108. goto err;
  109. if (i3.next(&i3) < 0)
  110. goto err;
  111. /* Consult zodb/btrees/interfaces.py for the meaning of the last
  112. * argument passed to merge_error().
  113. */
  114. /* TODO: This isn't passing on errors raised by value comparisons. */
  115. while (i1.position >= 0 && i2.position >= 0 && i3.position >= 0)
  116. {
  117. TEST_KEY_SET_OR(cmp12, i1.key, i2.key) goto err;
  118. TEST_KEY_SET_OR(cmp13, i1.key, i3.key) goto err;
  119. if (cmp12==0)
  120. {
  121. if (cmp13==0)
  122. {
  123. if (set || (TEST_VALUE(i1.value, i2.value) == 0))
  124. { /* change in i3 value or all same */
  125. if (merge_output(r, &i3, mapping) < 0) goto err;
  126. }
  127. else if (set || (TEST_VALUE(i1.value, i3.value) == 0))
  128. { /* change in i2 value */
  129. if (merge_output(r, &i2, mapping) < 0) goto err;
  130. }
  131. else
  132. { /* conflicting value changes in i2 and i3 */
  133. merge_error(i1.position, i2.position, i3.position, 1);
  134. goto err;
  135. }
  136. if (i1.next(&i1) < 0) goto err;
  137. if (i2.next(&i2) < 0) goto err;
  138. if (i3.next(&i3) < 0) goto err;
  139. }
  140. else if (cmp13 > 0)
  141. { /* insert i3 */
  142. if (merge_output(r, &i3, mapping) < 0) goto err;
  143. if (i3.next(&i3) < 0) goto err;
  144. }
  145. else if (set || (TEST_VALUE(i1.value, i2.value) == 0))
  146. { /* deleted in i3 */
  147. if (i3.position == 1)
  148. {
  149. /* Deleted the first item. This will modify the
  150. parent node, so we don't know if merging will be
  151. safe
  152. */
  153. merge_error(i1.position, i2.position, i3.position, 13);
  154. goto err;
  155. }
  156. if (i1.next(&i1) < 0) goto err;
  157. if (i2.next(&i2) < 0) goto err;
  158. }
  159. else
  160. { /* conflicting del in i3 and change in i2 */
  161. merge_error(i1.position, i2.position, i3.position, 2);
  162. goto err;
  163. }
  164. }
  165. else if (cmp13 == 0)
  166. {
  167. if (cmp12 > 0)
  168. { /* insert i2 */
  169. if (merge_output(r, &i2, mapping) < 0) goto err;
  170. if (i2.next(&i2) < 0) goto err;
  171. }
  172. else if (set || (TEST_VALUE(i1.value, i3.value) == 0))
  173. { /* deleted in i2 */
  174. if (i2.position == 1)
  175. {
  176. /* Deleted the first item. This will modify the
  177. parent node, so we don't know if merging will be
  178. safe
  179. */
  180. merge_error(i1.position, i2.position, i3.position, 13);
  181. goto err;
  182. }
  183. if (i1.next(&i1) < 0) goto err;
  184. if (i3.next(&i3) < 0) goto err;
  185. }
  186. else
  187. { /* conflicting del in i2 and change in i3 */
  188. merge_error(i1.position, i2.position, i3.position, 3);
  189. goto err;
  190. }
  191. }
  192. else
  193. { /* Both keys changed */
  194. TEST_KEY_SET_OR(cmp23, i2.key, i3.key) goto err;
  195. if (cmp23==0)
  196. { /* dueling inserts or deletes */
  197. merge_error(i1.position, i2.position, i3.position, 4);
  198. goto err;
  199. }
  200. if (cmp12 > 0)
  201. { /* insert i2 */
  202. if (cmp23 > 0)
  203. { /* insert i3 first */
  204. if (merge_output(r, &i3, mapping) < 0) goto err;
  205. if (i3.next(&i3) < 0) goto err;
  206. }
  207. else
  208. { /* insert i2 first */
  209. if (merge_output(r, &i2, mapping) < 0) goto err;
  210. if (i2.next(&i2) < 0) goto err;
  211. }
  212. }
  213. else if (cmp13 > 0)
  214. { /* Insert i3 */
  215. if (merge_output(r, &i3, mapping) < 0) goto err;
  216. if (i3.next(&i3) < 0) goto err;
  217. }
  218. else
  219. { /* 1<2 and 1<3: both deleted 1.key */
  220. merge_error(i1.position, i2.position, i3.position, 5);
  221. goto err;
  222. }
  223. }
  224. }
  225. while (i2.position >= 0 && i3.position >= 0)
  226. { /* New inserts */
  227. TEST_KEY_SET_OR(cmp23, i2.key, i3.key) goto err;
  228. if (cmp23==0)
  229. { /* dueling inserts */
  230. merge_error(i1.position, i2.position, i3.position, 6);
  231. goto err;
  232. }
  233. if (cmp23 > 0)
  234. { /* insert i3 */
  235. if (merge_output(r, &i3, mapping) < 0) goto err;
  236. if (i3.next(&i3) < 0) goto err;
  237. }
  238. else
  239. { /* insert i2 */
  240. if (merge_output(r, &i2, mapping) < 0) goto err;
  241. if (i2.next(&i2) < 0) goto err;
  242. }
  243. }
  244. while (i1.position >= 0 && i2.position >= 0)
  245. { /* remainder of i1 deleted in i3 */
  246. TEST_KEY_SET_OR(cmp12, i1.key, i2.key) goto err;
  247. if (cmp12 > 0)
  248. { /* insert i2 */
  249. if (merge_output(r, &i2, mapping) < 0) goto err;
  250. if (i2.next(&i2) < 0) goto err;
  251. }
  252. else if (cmp12==0 && (set || (TEST_VALUE(i1.value, i2.value) == 0)))
  253. { /* delete i3 */
  254. if (i1.next(&i1) < 0) goto err;
  255. if (i2.next(&i2) < 0) goto err;
  256. }
  257. else
  258. { /* Dueling deletes or delete and change */
  259. merge_error(i1.position, i2.position, i3.position, 7);
  260. goto err;
  261. }
  262. }
  263. while (i1.position >= 0 && i3.position >= 0)
  264. { /* remainder of i1 deleted in i2 */
  265. TEST_KEY_SET_OR(cmp13, i1.key, i3.key) goto err;
  266. if (cmp13 > 0)
  267. { /* insert i3 */
  268. if (merge_output(r, &i3, mapping) < 0) goto err;
  269. if (i3.next(&i3) < 0) goto err;
  270. }
  271. else if (cmp13==0 && (set || (TEST_VALUE(i1.value, i3.value) == 0)))
  272. { /* delete i2 */
  273. if (i1.next(&i1) < 0) goto err;
  274. if (i3.next(&i3) < 0) goto err;
  275. }
  276. else
  277. { /* Dueling deletes or delete and change */
  278. merge_error(i1.position, i2.position, i3.position, 8);
  279. goto err;
  280. }
  281. }
  282. if (i1.position >= 0)
  283. { /* Dueling deletes */
  284. merge_error(i1.position, i2.position, i3.position, 9);
  285. goto err;
  286. }
  287. while (i2.position >= 0)
  288. { /* Inserting i2 at end */
  289. if (merge_output(r, &i2, mapping) < 0) goto err;
  290. if (i2.next(&i2) < 0) goto err;
  291. }
  292. while (i3.position >= 0)
  293. { /* Inserting i3 at end */
  294. if (merge_output(r, &i3, mapping) < 0) goto err;
  295. if (i3.next(&i3) < 0) goto err;
  296. }
  297. /* If the output bucket is empty, conflict resolution doesn't have
  298. * enough info to unlink it from its containing BTree correctly.
  299. */
  300. if (r->len == 0)
  301. {
  302. merge_error(-1, -1, -1, 10);
  303. goto err;
  304. }
  305. finiSetIteration(&i1);
  306. finiSetIteration(&i2);
  307. finiSetIteration(&i3);
  308. if (s1->next)
  309. {
  310. Py_INCREF(s1->next);
  311. r->next = s1->next;
  312. }
  313. s = bucket_getstate(r);
  314. Py_DECREF(r);
  315. return s;
  316. err:
  317. finiSetIteration(&i1);
  318. finiSetIteration(&i2);
  319. finiSetIteration(&i3);
  320. Py_XDECREF(r);
  321. return NULL;
  322. }