dnp_sim2.c 24 KB

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