dnp_sim.c 26 KB

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