dnp_sim2.c 24 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009
  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. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. /* dnp_simulation.c - this file varifies the correctness of dnp algorithm
  42. by generating random sequences of operations, applying
  43. the algorithm and outputing the result
  44. usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]
  45. -h - print usage information.
  46. -n <number of simulations> - how many simulations to perform; default - 1.
  47. -v - verbose mode (prints full entry state after each operation execution)
  48. -f <output file> - file where results are stored; by default results are
  49. printed to the screen.
  50. -o <op file> - file that contains operation sequence to execute; by default,
  51. random sequence is generated.
  52. */
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <errno.h>
  56. #include <memory.h>
  57. #include <string.h>
  58. #include <time.h>
  59. #include <windows.h>
  60. #define MAX_OPS 18 /* maximum number of operations in a simulation */
  61. #define MAX_VALS 10 /* maximum number of values is entry or dn */
  62. #define NOT_PRESENT -1
  63. /* data types */
  64. typedef struct value_state
  65. {
  66. int value_index; /* value */
  67. int presence_csn; /* last time at which we know the value was present */
  68. int distinguished_index; /* index into dncsn list */
  69. int delete_csn; /* last attempt to delete this value */
  70. int present; /* flag that tells whether the value iscurrently present */
  71. } Value_State;
  72. typedef struct dn_csn
  73. {
  74. int csn; /* dn csn */
  75. int value_index; /* dn value */
  76. } Dn_Csn;
  77. typedef struct entry_state
  78. {
  79. Dn_Csn dn_csns [MAX_VALS + 1]; /* list of dn csns for this entry */
  80. int dn_csn_count; /* csn of the current dn */
  81. Value_State values[MAX_VALS]; /* values of the attribute */
  82. int attr_delete_csn; /* last attempt to delete the entire attribute */
  83. } Entry_State;
  84. typedef enum
  85. {
  86. OP_ADD_VALUE,
  87. OP_DELETE_VALUE,
  88. OP_RENAME_ENTRY,
  89. OP_DELETE_ATTR,
  90. OP_END
  91. } Operation_Type;
  92. typedef struct operation
  93. {
  94. Operation_Type type; /* operation type */
  95. int csn; /* operation type */
  96. int value_index; /* value to add, remove or rename from */
  97. }Operation;
  98. typedef struct simulator_params
  99. {
  100. int runs; /* number of runs */
  101. FILE *fout; /* output file */
  102. int value_count; /* number of values */
  103. int verbose; /* verbose mode */
  104. Operation *ops; /* operation sequence to apply */
  105. int op_count;
  106. }Simulator_Params;
  107. /* gloabl data */
  108. Simulator_Params sim;
  109. char *g_values[] =
  110. {
  111. "v",
  112. "u",
  113. "w",
  114. NULL
  115. };
  116. /* forward declarations */
  117. /* initialization */
  118. void process_cmd (int argc, char **argv);
  119. void set_default_sim_params ();
  120. int count_values ();
  121. void parse_operations_file (char *name);
  122. void parse_operation (char *line, int pos);
  123. int value2index (char *value);
  124. void print_usage ();
  125. /* simulation run */
  126. void run_simulation ();
  127. void generate_operations (Operation **ops, int *op_count);
  128. void generate_operation (Operation *op, int csn);
  129. int* generate_operation_order (int op_count, int seq_num);
  130. void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry);
  131. void init_entry_state (Entry_State *entry);
  132. void init_value_state (Value_State *val, int seq_num);
  133. void apply_operation (Entry_State *entry, Operation *op);
  134. void free_operations (Operation **ops);
  135. int ** new_perm_table (int op_count);
  136. void free_perm_table (int ***perm_table, int op_count);
  137. int get_perm_count (int op_count);
  138. void generate_perm_table (int *elements, int element_count, int static_part,
  139. int **perm_table);
  140. void apply_add_operation (Entry_State *entry, Operation *op);
  141. void apply_value_delete_operation (Entry_State *entry, Operation *op);
  142. void apply_attr_delete_operation (Entry_State *entry, Operation *op);
  143. void apply_rename_operation (Entry_State *entry, Operation *op);
  144. void purge_value_state (Entry_State *entry, int index);
  145. void resolve_value_state (Entry_State *entry, int value_index);
  146. int value_distinguished_at_delete (Entry_State *entry, int value_index);
  147. int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run);
  148. /* dnc_csn handling */
  149. int dn_csn_add (Entry_State *entry, int value_index, int csn);
  150. int get_value_dn_csn (Entry_State *entry, int value_index);
  151. /* data tracing */
  152. void dump_operations (Operation *ops, int op_count, int *order);
  153. void dump_operation (Operation *op);
  154. void dump_perm_table (int **perm_table, int op_count);
  155. void dump_entry_state (Entry_State *entry);
  156. void dump_value_state (Value_State *value);
  157. void dump_dn_csn_list (Entry_State *entry);
  158. /* misc functions */
  159. int max_val (int a, int b);
  160. int main (int argc, char **argv)
  161. {
  162. int i;
  163. process_cmd (argc, argv);
  164. for (i = 0; i < sim.runs; i++)
  165. {
  166. fprintf (sim.fout, "*******running simulation #%d ...\n\n", i+1);
  167. run_simulation ();
  168. fprintf (sim.fout, "\n*******done with simulation #%d ...\n\n", i+1);
  169. }
  170. if (sim.fout != stdout)
  171. fclose (sim.fout);
  172. return 0;
  173. }
  174. void process_cmd (int argc, char **argv)
  175. {
  176. int i;
  177. set_default_sim_params ();
  178. if (argc == 1)
  179. {
  180. return;
  181. }
  182. if (strcmp (argv[1], "-h") == 0) /* print help */
  183. {
  184. print_usage ();
  185. exit (0);
  186. }
  187. i = 1;
  188. while (i < argc)
  189. {
  190. if (strcmp (argv[i], "-v") == 0) /* verbose mode */
  191. {
  192. sim.verbose = 1;
  193. i ++;
  194. }
  195. else if (strcmp (argv[i], "-n") == 0)
  196. {
  197. if (i < argc - 1)
  198. {
  199. int runs = atoi (argv[i + 1]);
  200. if (runs > 0)
  201. sim.runs = runs;
  202. i+=2;
  203. }
  204. else
  205. {
  206. /* ONREPL print warning */
  207. i++;
  208. }
  209. }
  210. else if (strcmp (argv[i], "-f") == 0) /* output file */
  211. {
  212. if (i < argc - 1)
  213. {
  214. FILE *f = fopen (argv[i + 1], "w");
  215. if (f == 0)
  216. {
  217. printf ("failed to open output file; error - %s, using stdout\n",
  218. strerror(errno));
  219. }
  220. else
  221. {
  222. /* ONREPL print warning */
  223. sim.fout = f;
  224. }
  225. i += 2;
  226. }
  227. else
  228. i++;
  229. }
  230. else if (strcmp (argv[i], "-o") == 0) /* file with operation sequence */
  231. {
  232. if (i < argc - 1)
  233. {
  234. parse_operations_file (argv[i+1]);
  235. i += 2;
  236. }
  237. else
  238. {
  239. /* ONREPL print warning */
  240. i ++;
  241. }
  242. }
  243. else /* unknown option */
  244. {
  245. printf ("unknown option - %s; ignored\n", argv[i]);
  246. i ++;
  247. }
  248. }
  249. }
  250. void set_default_sim_params ()
  251. {
  252. memset (&sim, 0, sizeof (sim));
  253. sim.runs = 1;
  254. sim.fout = stdout;
  255. sim.value_count = count_values ();
  256. }
  257. /* file format: <op count>
  258. add <value>
  259. delete <value>
  260. delete attribute
  261. rename to <value>
  262. all spaces are significant
  263. */
  264. void parse_operations_file (char *name)
  265. {
  266. FILE *file = fopen (name, "r");
  267. char line [256];
  268. int i;
  269. if (file == NULL)
  270. {
  271. printf ("failed to open operations file %s: error = %d\n", name, errno);
  272. print_usage ();
  273. exit (1);
  274. }
  275. i = 0;
  276. while (fgets (line, sizeof (line), file))
  277. {
  278. if (i == 0)
  279. {
  280. /* read operation count */
  281. sim.op_count = atoi (line);
  282. if (sim.op_count < 1 || sim.op_count > MAX_OPS/2)
  283. {
  284. printf ("invalid operation count - %d; value must be between 1 and %d\n",
  285. sim.op_count, MAX_OPS/2);
  286. print_usage ();
  287. exit (1);
  288. }
  289. else
  290. {
  291. sim.ops = (Operation*)malloc (sim.op_count * sizeof (Operation));
  292. }
  293. }
  294. else
  295. {
  296. if (strlen (line) == 0) /* skip empty lines */
  297. continue;
  298. parse_operation (line, i);
  299. }
  300. i ++;
  301. }
  302. }
  303. void parse_operation (char *line, int i)
  304. {
  305. sim.ops [i - 1].csn = i;
  306. if (line[strlen(line) - 1] == '\n')
  307. line[strlen(line) - 1] = '\0';
  308. if (strncmp (line, "add", 3) == 0)
  309. {
  310. sim.ops [i - 1].type = OP_ADD_VALUE;
  311. sim.ops [i - 1].value_index = value2index (&line[4]);
  312. }
  313. else if (strncmp (line, "delete attribute", 16) == 0)
  314. {
  315. sim.ops [i - 1].type = OP_DELETE_ATTR;
  316. }
  317. else if (strncmp (line, "delete", 6) == 0)
  318. {
  319. sim.ops [i - 1].type = OP_DELETE_VALUE;
  320. sim.ops [i - 1].value_index = value2index (&line[7]);
  321. }
  322. else if (strncmp (line, "rename to", 6) == 0)
  323. {
  324. sim.ops [i - 1].type = OP_RENAME_ENTRY;
  325. sim.ops [i - 1].value_index = value2index (&line[10]);
  326. }
  327. else
  328. {
  329. /* invalid line */
  330. printf ("invalid operation: %s\n", line);
  331. exit (1);
  332. }
  333. }
  334. int value2index (char *value)
  335. {
  336. int i;
  337. for (i = 0; i < sim.value_count; i++)
  338. {
  339. if (strcmp (g_values[i], value) == 0)
  340. return i;
  341. }
  342. return -1;
  343. }
  344. void print_usage ()
  345. {
  346. printf ("usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]\n"
  347. "\t-h - print usage information\n"
  348. "\t-n <number of simulations>; default - 1\n"
  349. "\t-v - verbose mode\n"
  350. "\t-f <output file> - by default, results are printed to the screen\n"
  351. "\t-o <op file> - file that contains operation sequence to execute;\n"
  352. "\tby default, random sequence is generated.\n");
  353. }
  354. int count_values ()
  355. {
  356. int i;
  357. for (i = 0; g_values[i]; i++);
  358. return i;
  359. }
  360. void run_simulation ()
  361. {
  362. int *order;
  363. int i;
  364. int perm_count;
  365. Entry_State entry_first, entry_current;
  366. int error = 0;
  367. init_entry_state (&entry_first);
  368. fprintf (sim.fout, "initial entry state :\n");
  369. dump_entry_state (&entry_first);
  370. if (sim.ops == NULL)
  371. {
  372. generate_operations (&sim.ops, &sim.op_count);
  373. }
  374. fprintf (sim.fout, "initial operation set:\n");
  375. dump_operations (sim.ops, sim.op_count, NULL/* order */);
  376. //DebugBreak ();
  377. perm_count = get_perm_count (sim.op_count);
  378. for (i = 0; i < perm_count; i++)
  379. {
  380. fprintf (sim.fout, "--------------------------------\n");
  381. fprintf (sim.fout, "simulation run %d\n", i + 1);
  382. fprintf (sim.fout, "--------------------------------\n");
  383. order = generate_operation_order (sim.op_count, i);
  384. if (i == 0)
  385. apply_operation_sequence (sim.ops, sim.op_count, order, &entry_first);
  386. else
  387. {
  388. apply_operation_sequence (sim.ops, sim.op_count, order, &entry_current);
  389. error |= compare_entry_state (&entry_first, &entry_current, i + 1);
  390. }
  391. }
  392. switch (error)
  393. {
  394. case 0: fprintf (sim.fout, "all runs left the entry in the same state\n");
  395. break;
  396. case 1: fprintf (sim.fout, "while value presence is consistent across all runs, "
  397. "the exact state does not match\n");
  398. break;
  399. case 3: fprintf (sim.fout, "the runs left entries in an inconsistent state\n");
  400. break;
  401. }
  402. free_operations (&sim.ops);
  403. }
  404. void generate_operations (Operation **ops, int *op_count)
  405. {
  406. int i;
  407. /* generate number operations in the sequence */
  408. *op_count = slapi_rand () % (MAX_OPS / 2) + 1;
  409. *ops = (Operation *)malloc (*op_count * sizeof (Operation));
  410. for (i = 0; i < *op_count; i ++)
  411. {
  412. generate_operation (&((*ops)[i]), i + 1);
  413. }
  414. }
  415. void generate_operation (Operation *op, int csn)
  416. {
  417. /* generate operation type */
  418. op->type = slapi_rand () % OP_END;
  419. /* generate value to which operation applies */
  420. op->value_index = slapi_rand () % sim.value_count;
  421. op->csn = csn;
  422. }
  423. int* generate_operation_order (int op_count, int seq_num)
  424. {
  425. static int **perm_table = NULL;
  426. /* first request - generate pemutation table */
  427. if (seq_num == 0)
  428. {
  429. int elements [MAX_OPS];
  430. int i;
  431. if (perm_table)
  432. free_perm_table (&perm_table, op_count);
  433. perm_table = new_perm_table (op_count);
  434. for (i = 0; i < op_count; i++)
  435. elements [i] = i;
  436. generate_perm_table (elements, op_count, 0 /* static part */,
  437. perm_table);
  438. }
  439. return perm_table [seq_num];
  440. }
  441. void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry)
  442. {
  443. int i;
  444. init_entry_state (entry);
  445. if (!sim.verbose)
  446. {
  447. if (!sim.verbose)
  448. {
  449. fprintf (sim.fout, "operation_sequence for this run:\n");
  450. dump_operations (ops, op_count, order);
  451. }
  452. }
  453. for (i = 0; i < op_count; i++)
  454. {
  455. apply_operation (entry, &(ops [order[i]]));
  456. }
  457. if (!sim.verbose)
  458. {
  459. fprintf (sim.fout, "final entry state :\n");
  460. dump_entry_state (entry);
  461. }
  462. }
  463. void init_entry_state (Entry_State *entry)
  464. {
  465. int i;
  466. memset (entry, 0, sizeof (*entry));
  467. entry->attr_delete_csn = NOT_PRESENT;
  468. entry->dn_csn_count = 1;
  469. for (i = 0; i < sim.value_count; i++)
  470. {
  471. init_value_state (&(entry->values[i]), i);
  472. }
  473. }
  474. void init_value_state (Value_State *val, int seq_num)
  475. {
  476. memset (val, 0, sizeof (*val));
  477. val->value_index = seq_num;
  478. val->present = 1;
  479. val->delete_csn = NOT_PRESENT;
  480. if (seq_num > 0) /* only first value is distinguished */
  481. val->distinguished_index = -1;
  482. }
  483. void apply_operation (Entry_State *entry, Operation *op)
  484. {
  485. switch (op->type)
  486. {
  487. case OP_ADD_VALUE: apply_add_operation (entry, op);
  488. break;
  489. case OP_DELETE_VALUE: apply_value_delete_operation (entry, op);
  490. break;
  491. case OP_DELETE_ATTR: apply_attr_delete_operation (entry, op);
  492. break;
  493. case OP_RENAME_ENTRY: apply_rename_operation (entry, op);
  494. break;
  495. }
  496. if (sim.verbose)
  497. {
  498. fprintf (sim.fout, "operation: ");
  499. dump_operation (op);
  500. fprintf (sim.fout, "\n");
  501. dump_entry_state (entry);
  502. }
  503. }
  504. void free_operations (Operation **ops)
  505. {
  506. free (*ops);
  507. *ops = NULL;
  508. }
  509. int **new_perm_table (int op_count)
  510. {
  511. int i;
  512. int **perm_table;
  513. int perm_count = get_perm_count (op_count);
  514. perm_table = (int**)malloc (perm_count * sizeof (int*));
  515. for (i = 0; i < perm_count; i ++)
  516. perm_table [i] = (int*) malloc (op_count * sizeof (int));
  517. return perm_table;
  518. }
  519. void free_perm_table (int ***perm_table, int op_count)
  520. {
  521. int i;
  522. int perm_count = get_perm_count (op_count);
  523. for (i = 0; i < perm_count; i ++)
  524. free ((*perm_table)[i]);
  525. free (*perm_table);
  526. *perm_table = NULL;
  527. }
  528. void generate_perm_table (int *elements, int element_count, int static_part,
  529. int **perm_table)
  530. {
  531. int i;
  532. int elements_copy [MAX_OPS];
  533. int start_pos;
  534. if (element_count - 1 == static_part)
  535. {
  536. memcpy (*perm_table, elements, element_count * sizeof (int));
  537. return;
  538. }
  539. start_pos = 0;
  540. for (i = 0; i < element_count - static_part; i ++)
  541. {
  542. memcpy (elements_copy, elements, element_count * sizeof (int));
  543. elements_copy [static_part] = elements [static_part + i];
  544. elements_copy [static_part + i] = elements [static_part];
  545. generate_perm_table (elements_copy, element_count, static_part + 1,
  546. &perm_table [start_pos]);
  547. start_pos += get_perm_count (element_count - static_part - 1);
  548. }
  549. }
  550. int get_perm_count (int op_count)
  551. {
  552. int i;
  553. int perm_count = 1;
  554. for (i = 2; i <= op_count; i ++)
  555. perm_count *= i;
  556. return perm_count;
  557. }
  558. void apply_add_operation (Entry_State *entry, Operation *op)
  559. {
  560. if (entry->values[op->value_index].presence_csn < op->csn)
  561. {
  562. entry->values[op->value_index].presence_csn = op->csn;
  563. resolve_value_state (entry, op->value_index);
  564. }
  565. }
  566. void apply_value_delete_operation (Entry_State *entry, Operation *op)
  567. {
  568. if (entry->values[op->value_index].delete_csn < op->csn)
  569. {
  570. entry->values[op->value_index].delete_csn = op->csn;
  571. resolve_value_state (entry, op->value_index);
  572. }
  573. }
  574. void apply_attr_delete_operation (Entry_State *entry, Operation *op)
  575. {
  576. int i;
  577. if (entry->attr_delete_csn < op->csn)
  578. {
  579. entry->attr_delete_csn = op->csn;
  580. for (i = 0; i < sim.value_count; i++)
  581. {
  582. resolve_value_state (entry, i);
  583. }
  584. }
  585. }
  586. void apply_rename_operation (Entry_State *entry, Operation *op)
  587. {
  588. int index;
  589. if (entry->values[op->value_index].presence_csn == NOT_PRESENT)
  590. entry->values[op->value_index].presence_csn = op->csn;
  591. index = dn_csn_add (entry, op->value_index, op->csn);
  592. if (index > 0)
  593. resolve_value_state (entry, entry->dn_csns[index - 1].value_index);
  594. resolve_value_state (entry, entry->dn_csns[index].value_index);
  595. }
  596. void purge_value_state (Entry_State *entry, int value_index)
  597. {
  598. Value_State *value = &(entry->values[value_index]);
  599. int value_distinguished_csn = get_value_dn_csn (entry, value_index);
  600. if (value_distinguished_csn == -1 && value->presence_csn > value->delete_csn)
  601. value->delete_csn = NOT_PRESENT;
  602. else if (value->delete_csn < max_val (value_distinguished_csn, value->presence_csn))
  603. value->delete_csn = NOT_PRESENT;
  604. }
  605. void resolve_value_state (Entry_State *entry, int value_index)
  606. {
  607. Value_State *value = &(entry->values[value_index]);
  608. int value_distinguished_csn = get_value_dn_csn (entry, value_index);
  609. purge_value_state (entry, value_index);
  610. /* no deletes that effect the state */
  611. if (max_val (value->delete_csn, entry->attr_delete_csn) <
  612. max_val (value_distinguished_csn, value->presence_csn))
  613. {
  614. value->present = 1;
  615. return;
  616. }
  617. if (value->present) /* check if it should be removed based on the current state */
  618. {
  619. if (!value_distinguished_at_delete (entry, value_index))
  620. {
  621. value->present = 0;
  622. }
  623. }
  624. else /* not present - check if it should be restored */
  625. {
  626. if (value_distinguished_at_delete (entry, value_index))
  627. {
  628. value->present = 1;
  629. }
  630. }
  631. }
  632. int value_distinguished_at_delete (Entry_State *entry, int value_index)
  633. {
  634. Value_State *value = &(entry->values[value_index]);
  635. int value_distinguished_csn = get_value_dn_csn (entry, value_index);
  636. int delete_csn;
  637. int i;
  638. /* value has never been distinguished */
  639. if (value_distinguished_csn == -1)
  640. return 0;
  641. delete_csn = max_val (entry->attr_delete_csn, value->delete_csn);
  642. for (i = 0; i < entry->dn_csn_count; i++)
  643. {
  644. if (entry->dn_csns[i].csn > delete_csn)
  645. break;
  646. }
  647. /* i is never equal to 0 because the csn of the first element is always
  648. smaller than csn of any operation we can receive */
  649. return (entry->dn_csns[i-1].value_index == value_index);
  650. }
  651. int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run)
  652. {
  653. int i;
  654. int error = 0;
  655. /* first - quick check for present / not present */
  656. for (i = 0; i < sim.value_count; i++)
  657. {
  658. if (entry1->values[i].present != entry2->values[i].present)
  659. {
  660. fprintf (sim.fout,
  661. "value %s is %s present in the first run but %s present in the %d run\n",
  662. g_values[i], entry1->values[i].present ? "" : "not",
  663. entry2->values[i].present ? "" : "not", run);
  664. error = 1;
  665. }
  666. }
  667. if (error)
  668. return 3;
  669. /* compare dnc_csn list */
  670. if (entry1->dn_csn_count != entry2->dn_csn_count)
  671. {
  672. fprintf (sim.fout, "dn_csn count is %d for run 1 and %d for run %d\n",
  673. entry1->dn_csn_count, entry2->dn_csn_count, run);
  674. error = 1;
  675. }
  676. for (i = 0; i < entry1->dn_csn_count; i++)
  677. {
  678. if (entry1->dn_csns [i].csn != entry2->dn_csns [i].csn ||
  679. entry1->dn_csns [i].value_index != entry2->dn_csns [i].value_index)
  680. {
  681. fprintf (sim.fout,"elements %d of dn csn list are different:\n"
  682. "\tfirst run: csn - %d, value - %s\n"
  683. "\t%d run: csn - %d, value - %s\n", i,
  684. entry1->dn_csns [i].csn,
  685. g_values[entry1->dn_csns [i].value_index],
  686. run, entry2->dn_csns [i].csn,
  687. g_values[entry2->dn_csns [i].value_index]);
  688. error = 1;
  689. }
  690. }
  691. /* compare value state */
  692. if (entry1->attr_delete_csn != entry2->attr_delete_csn)
  693. {
  694. fprintf (sim.fout, "attribute delete csn is %d for run 1 "
  695. "but is %d for run %d\n", entry1->attr_delete_csn,
  696. entry2->attr_delete_csn, run);
  697. error = 1;
  698. }
  699. for (i = 0; i < sim.value_count; i++)
  700. {
  701. if (entry1->values[i].presence_csn != entry2->values[i].presence_csn)
  702. {
  703. fprintf (sim.fout, "presence csn for value %s is %d in run 1 "
  704. "but is %d in run %d\n", g_values[i], entry1->values[i].presence_csn,
  705. entry2->values[i].presence_csn, run);
  706. error = 1;
  707. }
  708. if (entry1->values[i].distinguished_index != entry2->values[i].distinguished_index)
  709. {
  710. fprintf (sim.fout, "distinguished index for value %s is %d in run 1 "
  711. "but is %d in run %d\n", g_values[i],
  712. entry1->values[i].distinguished_index,
  713. entry2->values[i].distinguished_index, run);
  714. error = 1;
  715. }
  716. if (entry1->values[i].delete_csn != entry2->values[i].delete_csn)
  717. {
  718. fprintf (sim.fout, "delete csn for value %s is %d in run 1 "
  719. "but is %d in run %d\n", g_values[i], entry1->values[i].delete_csn,
  720. entry2->values[i].delete_csn, run);
  721. error = 1;
  722. }
  723. }
  724. if (error != 0)
  725. {
  726. return 1;
  727. }
  728. else
  729. return 0;
  730. }
  731. int dn_csn_add (Entry_State *entry, int value_index, int csn)
  732. {
  733. int i, j;
  734. int distinguished_index;
  735. for (i = 0; i < entry->dn_csn_count; i++)
  736. {
  737. if (entry->dn_csns[i].csn > csn)
  738. break;
  739. }
  740. if (i < entry->dn_csn_count)
  741. {
  742. distinguished_index = i;
  743. for (j = i; j < entry->dn_csn_count; j ++)
  744. {
  745. if (entry->dn_csns[j].value_index == value_index)
  746. distinguished_index = j + 1;
  747. if (entry->values [entry->dn_csns[j].value_index].distinguished_index == j)
  748. entry->values [entry->dn_csns[j].value_index].distinguished_index ++;
  749. }
  750. memcpy (&(entry->dn_csns[i+1]), &(entry->dn_csns[i]),
  751. (entry->dn_csn_count - i) * sizeof (Dn_Csn));
  752. }
  753. else
  754. {
  755. distinguished_index = entry->dn_csn_count;
  756. }
  757. entry->values[value_index].distinguished_index = distinguished_index;
  758. entry->dn_csns[i].csn = csn;
  759. entry->dn_csns[i].value_index = value_index;
  760. entry->dn_csn_count ++;
  761. return i;
  762. }
  763. int get_value_dn_csn (Entry_State *entry, int value_index)
  764. {
  765. Value_State *value = &(entry->values [value_index]);
  766. if (value->distinguished_index == -1)
  767. return -1;
  768. else
  769. return entry->dn_csns [value->distinguished_index].csn;
  770. }
  771. void dump_operations (Operation *ops, int op_count, int *order)
  772. {
  773. int index;
  774. int i;
  775. for (i = 0; i < op_count; i ++)
  776. {
  777. if (order == NULL) /* current order */
  778. index = i;
  779. else
  780. index = order [i];
  781. dump_operation (&ops[index]);
  782. }
  783. fprintf (sim.fout, "\n");
  784. }
  785. void dump_operation (Operation *op)
  786. {
  787. switch (op->type)
  788. {
  789. case OP_ADD_VALUE:
  790. fprintf (sim.fout, "\t%d add value %s\n", op->csn,
  791. g_values [op->value_index]);
  792. break;
  793. case OP_DELETE_VALUE:
  794. fprintf (sim.fout, "\t%d delete value %s\n", op->csn,
  795. g_values [op->value_index]);
  796. break;
  797. case OP_DELETE_ATTR:
  798. fprintf (sim.fout, "\t%d delete attribute\n", op->csn);
  799. break;
  800. case OP_RENAME_ENTRY:
  801. fprintf (sim.fout, "\t%d rename entry to %s\n", op->csn,
  802. g_values [op->value_index]);
  803. break;
  804. }
  805. }
  806. void dump_perm_table (int **perm_table, int op_count)
  807. {
  808. int i, j;
  809. int perm_count = get_perm_count (op_count);
  810. for (i = 0; i < op_count; i++)
  811. {
  812. for (j = 0; j < perm_count; j++)
  813. {
  814. fprintf (sim.fout, "%d ", perm_table [j][i]);
  815. }
  816. fprintf (sim.fout, "\n");
  817. }
  818. }
  819. void dump_entry_state (Entry_State *entry)
  820. {
  821. int i;
  822. dump_dn_csn_list (entry);
  823. for (i = 0; i < sim.value_count; i++)
  824. {
  825. dump_value_state (&(entry->values[i]));
  826. }
  827. fprintf (sim.fout, "\n");
  828. }
  829. void dump_value_state (Value_State *value)
  830. {
  831. fprintf (sim.fout, "\tvalue %s is %s\n", g_values[value->value_index],
  832. value->present ? "present" : "not present");
  833. if (sim.verbose)
  834. {
  835. fprintf (sim.fout, "\t\tpresent csn: %d\n", value->presence_csn);
  836. fprintf (sim.fout, "\t\tdistinguished index: %d\n", value->distinguished_index);
  837. fprintf (sim.fout, "\t\tdelete value csn: %d\n", value->delete_csn);
  838. }
  839. }
  840. void dump_dn_csn_list (Entry_State *entry)
  841. {
  842. int i;
  843. fprintf (sim.fout, "\tdn csn list: \n");
  844. for (i = 0; i < entry->dn_csn_count; i++)
  845. {
  846. fprintf (sim.fout, "\t\tvalue: %s, csn: %d\n",
  847. g_values[entry->dn_csns[i].value_index], entry->dn_csns[i].csn);
  848. }
  849. }
  850. /* misc functions */
  851. int max_val (int a, int b)
  852. {
  853. if (a >= b)
  854. return a;
  855. else
  856. return b;
  857. }