1
0

dnp_sim.c 26 KB

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