durable_rules 0.34.29 → 0.34.31

Sign up to get free protection for your applications and to get access to all the features.
data/src/rules/json.c CHANGED
@@ -395,7 +395,7 @@ static unsigned int getString(char *start, char **first, char **last) {
395
395
  static unsigned int getStringAndHash(char *start, char **first, char **last, unsigned int *hash) {
396
396
  unsigned char state = ST_STRING_SEEK;
397
397
  char delimiter = '\0';
398
- unsigned int currentHash = 5381;
398
+ unsigned int currentHash = FNV_32_OFFSET_BASIS;
399
399
  while(start[0] != '\0') {
400
400
  switch (state) {
401
401
  case ST_STRING_SEEK:
@@ -417,11 +417,14 @@ static unsigned int getStringAndHash(char *start, char **first, char **last, uns
417
417
  state = ST_STRING_ESC;
418
418
  }
419
419
 
420
- currentHash = ((currentHash << 5) + currentHash) + (*start);
420
+ currentHash ^= (*start);
421
+ currentHash *= FNV_32_PRIME;
421
422
  break;
422
423
  case ST_STRING_ESC:
423
424
  state = ST_STRING_PARSE;
424
- currentHash = ((currentHash << 5) + currentHash) + (*start);
425
+
426
+ currentHash ^= (*start);
427
+ currentHash *= FNV_32_PRIME;
425
428
  break;
426
429
  }
427
430
 
@@ -430,3 +433,4 @@ static unsigned int getStringAndHash(char *start, char **first, char **last, uns
430
433
 
431
434
  return ERR_PARSE_STRING;
432
435
  }
436
+
data/src/rules/json.h CHANGED
@@ -17,6 +17,9 @@
17
17
  #define JSON_REGEX 0x0C
18
18
  #define JSON_IREGEX 0x0D
19
19
 
20
+ #define FNV_32_OFFSET_BASIS 0x811c9dc5
21
+ #define FNV_32_PRIME 16777619
22
+
20
23
  unsigned int readNextName(char *start, char **first, char **last, unsigned int *hash);
21
24
  unsigned int readNextValue(char *start, char **first, char **last, unsigned char *type);
22
25
  unsigned int readNextArrayValue(char *start, char **first, char **last, unsigned char *type);
data/src/rules/net.c CHANGED
@@ -686,7 +686,12 @@ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding)
686
686
  if (asprintf(&lua,
687
687
  "local sid = ARGV[1]\n"
688
688
  "local assert_fact = tonumber(ARGV[2])\n"
689
- "local keys_count = tonumber(ARGV[3])\n"
689
+ // when mark visited is set to 0, it means eval will be called immedately
690
+ // with the same message. In that case, the function will avid setting
691
+ // the visited bit (for events), storing the message and increasing the
692
+ // mid count (for the case of auto generated mid)
693
+ "local mark_visited = tonumber(ARGV[3])\n"
694
+ "local keys_count = tonumber(ARGV[4])\n"
690
695
  "local events_hashset = \"%s!e!\" .. sid\n"
691
696
  "local facts_hashset = \"%s!f!\" .. sid\n"
692
697
  "local visited_hashset = \"%s!v!\" .. sid\n"
@@ -694,12 +699,14 @@ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding)
694
699
  "local message = {}\n"
695
700
  "local primary_message_keys = {}\n"
696
701
  "local input_keys = {}\n"
697
- "local save_message = function(current_key, message, events_key, messages_key)\n"
698
- " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
702
+ "local save_message = function(current_key, message, events_key, messages_key, save_hashset)\n"
703
+ " if save_hashset == 1 then\n"
704
+ " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
705
+ " end\n"
699
706
  " local primary_key = primary_message_keys[current_key](message)\n"
700
707
  " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
701
708
  "end\n"
702
- "for index = 4 + keys_count, #ARGV, 3 do\n"
709
+ "for index = 5 + keys_count, #ARGV, 3 do\n"
703
710
  " if ARGV[index + 2] == \"1\" then\n"
704
711
  " message[ARGV[index]] = ARGV[index + 1]\n"
705
712
  " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
@@ -717,35 +724,41 @@ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding)
717
724
  " end\n"
718
725
  "end\n"
719
726
  "local mid = message[\"id\"]\n"
720
- "if not mid then\n"
721
- " mid = \"$m-\" .. redis.call(\"hincrby\", mid_count_hashset, sid, 1)\n"
727
+ "if mid == \"\" then\n"
728
+ " if mark_visited == 0 then\n"
729
+ " mid = \"$m-\" .. redis.call(\"hget\", mid_count_hashset, sid) + 1\n"
730
+ " else\n"
731
+ " mid = \"$m-\" .. redis.call(\"hincrby\", mid_count_hashset, sid, 1)\n"
732
+ " end\n"
722
733
  " message[\"id\"] = mid\n"
723
734
  "else\n"
724
- " if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
725
- " if assert_fact == 0 then\n"
726
- " if not redis.call(\"hget\", events_hashset, mid) then\n"
727
- " return %d\n"
728
- " end\n"
729
- " else\n"
730
- " if not redis.call(\"hget\", facts_hashset, mid) then\n"
735
+ " if assert_fact == 1 then\n"
736
+ " if redis.call(\"hexists\", facts_hashset, mid) == 1 then\n"
737
+ " return %d\n"
738
+ " end\n"
739
+ " else\n"
740
+ " if mark_visited == 1 then\n"
741
+ " if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
731
742
  " return %d\n"
732
743
  " end\n"
744
+ " elseif redis.call(\"hexists\", visited_hashset, mid) == 1 then \n"
745
+ " return %d\n"
733
746
  " end\n"
734
747
  " end\n"
735
748
  "end\n"
736
- "for index = 4, 3 + keys_count, 1 do\n"
749
+ "for index = 5, 4 + keys_count, 1 do\n"
737
750
  " input_keys[ARGV[index]] = true\n"
738
751
  "end\n"
739
752
  "%sif assert_fact == 1 then\n"
740
753
  " message[\"$f\"] = 1\n"
741
- " for index = 4, 3 + keys_count, 1 do\n"
754
+ " for index = 5, 4 + keys_count, 1 do\n"
742
755
  " local key = ARGV[index]\n"
743
- " save_message(key, message, key .. \"!f!\" .. sid, facts_hashset)\n"
756
+ " save_message(key, message, key .. \"!f!\" .. sid, facts_hashset, mark_visited)\n"
744
757
  " end\n"
745
758
  "else\n"
746
- " for index = 4, 3 + keys_count, 1 do\n"
759
+ " for index = 5, 4 + keys_count, 1 do\n"
747
760
  " local key = ARGV[index]\n"
748
- " save_message(key, message, key .. \"!e!\" .. sid, events_hashset)\n"
761
+ " save_message(key, message, key .. \"!e!\" .. sid, events_hashset, mark_visited)\n"
749
762
  " end\n"
750
763
  "end\n",
751
764
  name,
@@ -754,6 +767,7 @@ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding)
754
767
  name,
755
768
  ERR_EVENT_OBSERVED,
756
769
  ERR_EVENT_OBSERVED,
770
+ ERR_EVENT_OBSERVED,
757
771
  addMessageLua) == -1) {
758
772
  return ERR_OUT_OF_MEMORY;
759
773
  }
@@ -947,6 +961,7 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
947
961
  if (asprintf(&lua,
948
962
  "local facts_key = \"%s!f!\"\n"
949
963
  "local events_key = \"%s!e!\"\n"
964
+ "local visited_key = \"%s!v!\"\n"
950
965
  "local action_key = \"%s!a\"\n"
951
966
  "local state_key = \"%s!s\"\n"
952
967
  "local timers_key = \"%s!t\"\n"
@@ -1040,7 +1055,7 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1040
1055
  " if cancel then\n"
1041
1056
  " for i = 1, #frame, 1 do\n"
1042
1057
  " if type(frame[i]) == \"table\" then\n"
1043
- " redis.call(\"hsetnx\", events_hashset, frame[i][\"id\"], cmsgpack.pack(frame[i]))\n"
1058
+ " redis.call(\"hdel\", visited_key .. sid, frame[i][\"id\"])\n"
1044
1059
  " redis.call(\"zadd\", timers_key, max_score, \"p:\" .. cjson.encode(frame[i]))\n"
1045
1060
  " end\n"
1046
1061
  " end\n"
@@ -1211,6 +1226,7 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1211
1226
  name,
1212
1227
  name,
1213
1228
  name,
1229
+ name,
1214
1230
  peekActionLua) == -1) {
1215
1231
  return ERR_OUT_OF_MEMORY;
1216
1232
  }
@@ -2095,15 +2111,13 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2095
2111
  " message[\"id\"] = mid\n"
2096
2112
  " end\n"
2097
2113
  "else\n"
2098
- " if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
2099
- " if assert_fact == 0 then\n"
2100
- " if message and redis.call(\"hexists\", events_hashset, mid) == 0 then\n"
2101
- " return %d\n"
2102
- " end\n"
2103
- " else\n"
2104
- " if message and redis.call(\"hexists\", facts_hashset, mid) == 0 then\n"
2105
- " return %d\n"
2106
- " end\n"
2114
+ " if assert_fact == 1 then\n"
2115
+ " if message and redis.call(\"hexists\", facts_hashset, mid) == 1 then\n"
2116
+ " return %d\n"
2117
+ " end\n"
2118
+ " else\n"
2119
+ " if message and redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
2120
+ " return %d\n"
2107
2121
  " end\n"
2108
2122
  " end\n"
2109
2123
  "end\n"
@@ -2354,12 +2368,12 @@ unsigned int formatEvalMessage(void *rulesBinding,
2354
2368
  char *sid,
2355
2369
  char *mid,
2356
2370
  char *message,
2357
- jsonProperty *allProperties,
2358
- unsigned int propertiesLength,
2371
+ jsonObject *jo,
2359
2372
  unsigned char actionType,
2360
2373
  char **keys,
2361
2374
  unsigned int keysLength,
2362
2375
  char **command) {
2376
+ unsigned int propertiesLength = jo->propertiesLength;
2363
2377
  if (actionType == ACTION_RETRACT_FACT || actionType == ACTION_RETRACT_EVENT) {
2364
2378
  propertiesLength = 0;
2365
2379
  }
@@ -2404,16 +2418,16 @@ unsigned int formatEvalMessage(void *rulesBinding,
2404
2418
 
2405
2419
  unsigned int offset = 8 + keysLength;
2406
2420
  for (unsigned int i = 0; i < propertiesLength; ++i) {
2407
- argv[offset + i * 3] = allProperties[i].name;
2408
- argvl[offset + i * 3] = allProperties[i].nameLength;
2409
- argv[offset + i * 3 + 1] = message + allProperties[i].valueOffset;
2410
- if (allProperties[i].type == JSON_STRING) {
2411
- argvl[offset + i * 3 + 1] = allProperties[i].valueLength;
2421
+ argv[offset + i * 3] = jo->properties[i].name;
2422
+ argvl[offset + i * 3] = jo->properties[i].nameLength;
2423
+ argv[offset + i * 3 + 1] = jo->properties[i].valueString;
2424
+ if (jo->properties[i].type == JSON_STRING) {
2425
+ argvl[offset + i * 3 + 1] = jo->properties[i].valueLength;
2412
2426
  } else {
2413
- argvl[offset + i * 3 + 1] = allProperties[i].valueLength + 1;
2427
+ argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
2414
2428
  }
2415
2429
 
2416
- switch(allProperties[i].type) {
2430
+ switch(jo->properties[i].type) {
2417
2431
  case JSON_STRING:
2418
2432
  argv[offset + i * 3 + 2] = "1";
2419
2433
  break;
@@ -2446,22 +2460,23 @@ unsigned int formatEvalMessage(void *rulesBinding,
2446
2460
  unsigned int formatStoreMessage(void *rulesBinding,
2447
2461
  char *sid,
2448
2462
  char *message,
2449
- jsonProperty *allProperties,
2450
- unsigned int propertiesLength,
2463
+ jsonObject *jo,
2451
2464
  unsigned char storeFact,
2465
+ unsigned char markVisited,
2452
2466
  char **keys,
2453
2467
  unsigned int keysLength,
2454
2468
  char **command) {
2469
+ unsigned int propertiesLength = jo->propertiesLength;
2455
2470
  binding *bindingContext = (binding*)rulesBinding;
2456
2471
  char keysLengthString[5];
2457
2472
  #ifdef _WIN32
2458
2473
  sprintf_s(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2459
- char **argv = (char **)_alloca(sizeof(char*)*(6 + keysLength + propertiesLength * 3));
2460
- size_t *argvl = (size_t *)_alloca(sizeof(size_t)*(6 + keysLength + propertiesLength * 3));
2474
+ char **argv = (char **)_alloca(sizeof(char*)*(7 + keysLength + propertiesLength * 3));
2475
+ size_t *argvl = (size_t *)_alloca(sizeof(size_t)*(7 + keysLength + propertiesLength * 3));
2461
2476
  #else
2462
2477
  snprintf(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2463
- char *argv[6 + keysLength + propertiesLength * 3];
2464
- size_t argvl[6 + keysLength + propertiesLength * 3];
2478
+ char *argv[7 + keysLength + propertiesLength * 3];
2479
+ size_t argvl[7 + keysLength + propertiesLength * 3];
2465
2480
  #endif
2466
2481
 
2467
2482
  argv[0] = "evalsha";
@@ -2474,26 +2489,28 @@ unsigned int formatStoreMessage(void *rulesBinding,
2474
2489
  argvl[3] = strlen(sid);
2475
2490
  argv[4] = storeFact ? "1" : "0";
2476
2491
  argvl[4] = 1;
2477
- argv[5] = keysLengthString;
2478
- argvl[5] = strlen(keysLengthString);
2492
+ argv[5] = markVisited ? "1" : "0";
2493
+ argvl[5] = 1;
2494
+ argv[6] = keysLengthString;
2495
+ argvl[6] = strlen(keysLengthString);
2479
2496
 
2480
2497
  for (unsigned int i = 0; i < keysLength; ++i) {
2481
- argv[6 + i] = keys[i];
2482
- argvl[6 + i] = strlen(keys[i]);
2498
+ argv[7 + i] = keys[i];
2499
+ argvl[7 + i] = strlen(keys[i]);
2483
2500
  }
2484
2501
 
2485
- unsigned int offset = 6 + keysLength;
2502
+ unsigned int offset = 7 + keysLength;
2486
2503
  for (unsigned int i = 0; i < propertiesLength; ++i) {
2487
- argv[offset + i * 3] = allProperties[i].name;
2488
- argvl[offset + i * 3] = allProperties[i].nameLength;
2489
- argv[offset + i * 3 + 1] = message + allProperties[i].valueOffset;
2490
- if (allProperties[i].type == JSON_STRING) {
2491
- argvl[offset + i * 3 + 1] = allProperties[i].valueLength;
2504
+ argv[offset + i * 3] = jo->properties[i].name;
2505
+ argvl[offset + i * 3] = jo->properties[i].nameLength;
2506
+ argv[offset + i * 3 + 1] = jo->properties[i].valueString;
2507
+ if (jo->properties[i].type == JSON_STRING) {
2508
+ argvl[offset + i * 3 + 1] = jo->properties[i].valueLength;
2492
2509
  } else {
2493
- argvl[offset + i * 3 + 1] = allProperties[i].valueLength + 1;
2510
+ argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
2494
2511
  }
2495
2512
 
2496
- switch(allProperties[i].type) {
2513
+ switch(jo->properties[i].type) {
2497
2514
  case JSON_STRING:
2498
2515
  argv[offset + i * 3 + 2] = "1";
2499
2516
  break;
data/src/rules/net.h CHANGED
@@ -54,8 +54,7 @@ unsigned int formatEvalMessage(void *rulesBinding,
54
54
  char *sid,
55
55
  char *mid,
56
56
  char *message,
57
- jsonProperty *allProperties,
58
- unsigned int propertiesLength,
57
+ jsonObject *jo,
59
58
  unsigned char actionType,
60
59
  char **keys,
61
60
  unsigned int keysLength,
@@ -64,9 +63,9 @@ unsigned int formatEvalMessage(void *rulesBinding,
64
63
  unsigned int formatStoreMessage(void *rulesBinding,
65
64
  char *sid,
66
65
  char *message,
67
- jsonProperty *allProperties,
68
- unsigned int propertiesLength,
66
+ jsonObject *jo,
69
67
  unsigned char storeFact,
68
+ unsigned char markVisited,
70
69
  char **keys,
71
70
  unsigned int keysLength,
72
71
  char **command);
data/src/rules/rete.c CHANGED
@@ -8,34 +8,32 @@
8
8
  #include "json.h"
9
9
  #include "regex.h"
10
10
 
11
- #define HASH_ALL 193486302 // all
12
- #define HASH_ANY 193486381 // any
13
- #define HASH_PRI 193502832 // pri
14
- #define HASH_COUNT 255678574 // count
15
- #define HASH_SPAN 2090731639 // span
16
- #define HASH_CAP 193488121 // cap
17
- #define HASH_BY 5863264 // by
18
- #define HASH_LT 193419881 // $lt
19
- #define HASH_LTE 2087888878 // $lte
20
- #define HASH_GT 193419716 // $gt
21
- #define HASH_GTE 2087883433 // $gte
22
- #define HASH_EQ 193419647 // $eq
23
- #define HASH_NEQ 2087890573 // $neq
24
- #define HASH_MT 193419914 // $mt
25
- #define HASH_IMT 2087885395 // $imt
26
- #define HASH_EX 193419654 // $ex
27
- #define HASH_NEX 2087890580 // $nex
28
- #define HASH_OR 193419978 // $or
29
- #define HASH_AND 2087876700 // $and
30
- #define HASH_S 5861212 // $s
31
- #define HASH_NAME 2090536006 // name
32
- #define HASH_ADD 2087876370 // $add
33
- #define HASH_SUB 2087896531 // $sub
34
- #define HASH_MUL 2087890007 // $mul
35
- #define HASH_DIV 2087879820 // $div
36
- #define HASH_L 5861205 // $l
37
- #define HASH_R 5861211 //$r
38
- #define HASH_FORWARD 1810358942 // $forward
11
+ #define HASH_ALL 321211332 // all
12
+ #define HASH_ANY 740945997 // any
13
+ #define HASH_PRI 1450887882 // pri
14
+ #define HASH_COUNT 967958004 // count
15
+ #define HASH_CAP 41178555 // cap
16
+ #define HASH_LT 542787579 // $lt
17
+ #define HASH_LTE 2350824890 // $lte
18
+ #define HASH_GT 507407960 // $gt
19
+ #define HASH_GTE 3645344263 // $gte
20
+ #define HASH_EQ 256037865 // $eq
21
+ #define HASH_NEQ 2488026869 // $neq
22
+ #define HASH_MT 576092554 // $mt
23
+ #define HASH_IMT 1472564215 // $imt
24
+ #define HASH_EX 373481198 // $ex
25
+ #define HASH_NEX 2605470202 // $nex
26
+ #define HASH_OR 340911698 // $or
27
+ #define HASH_AND 3746487396 // $and
28
+ #define HASH_S 1186729920 // $s
29
+ #define HASH_NAME 2369371622 // name
30
+ #define HASH_ADD 4081054038 // $add
31
+ #define HASH_SUB 1040718071 // $sub
32
+ #define HASH_MUL 304370403 // $mul
33
+ #define HASH_DIV 130502 // $div
34
+ #define HASH_L 1706836109 // $l
35
+ #define HASH_R 1203507539 //$r
36
+ #define HASH_FORWARD 739185624 // $forward
39
37
 
40
38
  typedef struct path {
41
39
  unsigned char operator;
@@ -746,26 +744,15 @@ static unsigned int validateRuleset(char *rules) {
746
744
  return countResult;
747
745
  }
748
746
 
749
- unsigned int spanResult = validateSetting(HASH_SPAN, first, JSON_INT);
750
- if (spanResult != PARSE_OK && spanResult != ERR_SETTING_NOT_FOUND) {
751
- return spanResult;
752
- }
753
-
754
747
  unsigned int capResult = validateSetting(HASH_CAP, first, JSON_INT);
755
748
  if (capResult != PARSE_OK && capResult != ERR_SETTING_NOT_FOUND) {
756
749
  return capResult;
757
750
  }
758
751
 
759
- if ((spanResult == PARSE_OK && (countResult == PARSE_OK || capResult == PARSE_OK)) ||
760
- (countResult == PARSE_OK && capResult == PARSE_OK)) {
752
+ if (countResult == PARSE_OK && capResult == PARSE_OK) {
761
753
  return ERR_UNEXPECTED_NAME;
762
754
  }
763
755
 
764
- result = validateSetting(HASH_BY, first, JSON_STRING);
765
- if (result != PARSE_OK && result != ERR_SETTING_NOT_FOUND) {
766
- return result;
767
- }
768
-
769
756
  result = validateSetting(HASH_PRI, first, JSON_INT);
770
757
  if (result != PARSE_OK && result != ERR_SETTING_NOT_FOUND) {
771
758
  return result;
@@ -783,7 +770,7 @@ static unsigned int validateRuleset(char *rules) {
783
770
  if (result != RULES_OK && result != PARSE_END) {
784
771
  return result;
785
772
  }
786
- } else if (hash != HASH_COUNT && hash != HASH_PRI && hash != HASH_SPAN && hash != HASH_CAP && hash != HASH_BY) {
773
+ } else if (hash != HASH_COUNT && hash != HASH_PRI && hash != HASH_CAP) {
787
774
  return ERR_UNEXPECTED_NAME;
788
775
  }
789
776
 
@@ -1289,7 +1276,7 @@ static unsigned int createBetaConnector(ruleset *tree,
1289
1276
 
1290
1277
  if (operator == OP_ALL || operator == OP_ANY || operator == OP_NOT) {
1291
1278
  nameLength = nameLength - 4;
1292
- hash = djbHash(first, nameLength);
1279
+ hash = fnv1Hash32(first, nameLength);
1293
1280
  }
1294
1281
  }
1295
1282
 
@@ -1694,7 +1681,6 @@ static unsigned int createTree(ruleset *tree, char *rules) {
1694
1681
  ruleAction->value.c.cap = 0;
1695
1682
  getSetting(HASH_PRI, first, &ruleAction->value.c.priority);
1696
1683
  getSetting(HASH_COUNT, first, &ruleAction->value.c.count);
1697
- getSetting(HASH_SPAN, first, &ruleAction->value.c.span);
1698
1684
  getSetting(HASH_CAP, first, &ruleAction->value.c.cap);
1699
1685
  if (!ruleAction->value.c.count && !ruleAction->value.c.span && !ruleAction->value.c.cap) {
1700
1686
  ruleAction->value.c.count = 1;
data/src/rules/state.c CHANGED
@@ -6,15 +6,13 @@
6
6
  #include "json.h"
7
7
  #include "net.h"
8
8
 
9
- unsigned int djbHash(char *str, unsigned int len) {
10
- unsigned int hash = 5381;
11
- unsigned int i = 0;
12
-
13
- for(i = 0; i < len; str++, i++) {
14
- hash = ((hash << 5) + hash) + (*str);
15
- }
16
-
17
- return hash;
9
+ unsigned int fnv1Hash32(char *str, unsigned int len) {
10
+ unsigned int hash = FNV_32_OFFSET_BASIS;
11
+ for(unsigned int i = 0; i < len; str++, i++) {
12
+ hash ^= (*str);
13
+ hash *= FNV_32_PRIME;
14
+ }
15
+ return hash;
18
16
  }
19
17
 
20
18
  static unsigned int evictEntry(ruleset *tree) {
@@ -43,7 +41,7 @@ static unsigned int evictEntry(ruleset *tree) {
43
41
  current->sidHash = 0;
44
42
  current->bindingIndex = 0;
45
43
  current->lastRefresh = 0;
46
- current->propertiesLength = 0;
44
+ current->jo.propertiesLength = 0;
47
45
  found = 1;
48
46
  }
49
47
  }
@@ -164,15 +162,70 @@ static stateEntry *getEntry(ruleset *tree, char *sid, unsigned int sidHash) {
164
162
  return NULL;
165
163
  }
166
164
 
165
+ static unsigned int fixupIds(jsonObject *jo) {
166
+ jsonProperty *property;
167
+ // id and sid are coerced to strings
168
+ // to avoid unnecessary conversions
169
+ if (jo->sidIndex != UNDEFINED_INDEX && jo->properties[jo->sidIndex].type != JSON_NIL) {
170
+ //coerce value to string
171
+ property = &jo->properties[jo->sidIndex];
172
+ if (property->type == JSON_DOUBLE || property->type == JSON_INT) {
173
+ ++property->valueLength;
174
+ }
175
+
176
+ property->type = JSON_STRING;
177
+ } else {
178
+ property = &jo->properties[jo->propertiesLength];
179
+ jo->sidIndex = jo->propertiesLength;
180
+ ++jo->propertiesLength;
181
+ if (jo->propertiesLength == MAX_OBJECT_PROPERTIES) {
182
+ return ERR_EVENT_MAX_PROPERTIES;
183
+ }
184
+
185
+ strncpy(jo->sidBuffer, "0", 1);
186
+ property->hash = HASH_SID;
187
+ property->isMaterial = 1;
188
+ property->valueString = jo->sidBuffer;
189
+ property->valueLength = 1;
190
+ strncpy(property->name, "sid", 3);
191
+ property->nameLength = 3;
192
+ property->type = JSON_STRING;
193
+ }
194
+
195
+ if (jo->idIndex != UNDEFINED_INDEX && jo->properties[jo->idIndex].type != JSON_NIL) {
196
+ //coerce value to string
197
+ property = &jo->properties[jo->idIndex];
198
+ if (property->type == JSON_DOUBLE || property->type == JSON_INT) {
199
+ ++property->valueLength;
200
+ }
201
+
202
+ property->type = JSON_STRING;
203
+ } else {
204
+ property = &jo->properties[jo->propertiesLength];
205
+ jo->idIndex = jo->propertiesLength;
206
+ ++jo->propertiesLength;
207
+ if (jo->propertiesLength == MAX_OBJECT_PROPERTIES) {
208
+ return ERR_EVENT_MAX_PROPERTIES;
209
+ }
210
+
211
+ jo->idBuffer[0] = 0;
212
+ property->hash = HASH_ID;
213
+ property->isMaterial = 1;
214
+ property->valueString = jo->idBuffer;
215
+ property->valueLength = 0;
216
+ strncpy(property->name, "id", 2);
217
+ property->nameLength = 2;
218
+ property->type = JSON_STRING;
219
+ }
220
+
221
+ return RULES_OK;
222
+ }
223
+
167
224
  unsigned int constructObject(char *root,
168
225
  char *parentName,
169
226
  char *object,
170
- char createHashtable,
171
- unsigned int maxProperties,
172
- jsonProperty *properties,
173
- unsigned int *propertiesLength,
174
- unsigned int *midIndex,
175
- unsigned int *sidIndex,
227
+ char layout,
228
+ jsonObject *jo,
176
229
  char **next) {
177
230
  char *firstName;
178
231
  char *lastName;
@@ -180,7 +233,16 @@ unsigned int constructObject(char *root,
180
233
  char *last;
181
234
  unsigned char type;
182
235
  unsigned int hash;
183
- int parentNameLength = (parentName ? strlen(parentName): 0);
236
+ int parentNameLength;
237
+ if (parentName) {
238
+ parentNameLength = strlen(parentName);
239
+ } else {
240
+ parentNameLength = 0;
241
+ jo->idIndex = UNDEFINED_INDEX;
242
+ jo->sidIndex = UNDEFINED_INDEX;
243
+ jo->propertiesLength = 0;
244
+ }
245
+
184
246
  object = (object ? object : root);
185
247
  unsigned int result = readNextName(object, &firstName, &lastName, &hash);
186
248
  while (result == PARSE_OK) {
@@ -191,35 +253,40 @@ unsigned int constructObject(char *root,
191
253
 
192
254
  jsonProperty *property = NULL;
193
255
  if (type != JSON_OBJECT) {
194
- if (!createHashtable) {
195
- property = &properties[*propertiesLength];
196
- if (hash == HASH_ID) {
197
- *midIndex = *propertiesLength;
198
- } else if (hash == HASH_SID) {
199
- *sidIndex = *propertiesLength;
200
- }
201
- } else {
202
- unsigned int candidate = hash % maxProperties;
203
- while (properties[candidate].type != 0) {
204
- candidate = (candidate + 1) % maxProperties;
205
- }
206
-
207
- if (hash == HASH_ID) {
208
- *midIndex = candidate;
209
- } else if (hash == HASH_SID) {
210
- *sidIndex = candidate;
256
+ switch (layout) {
257
+ case JSON_OBJECT_SEQUENCED:
258
+ property = &jo->properties[jo->propertiesLength];
259
+ if (hash == HASH_ID) {
260
+ jo->idIndex = jo->propertiesLength;
261
+ } else if (hash == HASH_SID) {
262
+ jo->sidIndex = jo->propertiesLength;
263
+ }
264
+ break;
265
+ case JSON_OBJECT_HASHED:
266
+ {
267
+ unsigned int candidate = hash % MAX_OBJECT_PROPERTIES;
268
+ while (jo->properties[candidate].type != 0) {
269
+ candidate = (candidate + 1) % MAX_OBJECT_PROPERTIES;
270
+ }
271
+
272
+ if (hash == HASH_ID) {
273
+ jo->idIndex = candidate;
274
+ } else if (hash == HASH_SID) {
275
+ jo->sidIndex = candidate;
276
+ }
277
+
278
+ property = &jo->properties[candidate];
211
279
  }
212
-
213
- property = &properties[candidate];
214
- }
215
-
216
- *propertiesLength = *propertiesLength + 1;
217
- if (*propertiesLength == maxProperties) {
280
+ break;
281
+ }
282
+
283
+ ++jo->propertiesLength;
284
+ if (jo->propertiesLength == MAX_OBJECT_PROPERTIES) {
218
285
  return ERR_EVENT_MAX_PROPERTIES;
219
286
  }
220
287
 
221
288
  property->isMaterial = 0;
222
- property->valueOffset = first - root;
289
+ property->valueString = first;
223
290
  property->valueLength = last - first;
224
291
  property->type = type;
225
292
  }
@@ -244,15 +311,11 @@ unsigned int constructObject(char *root,
244
311
  strncpy(newParent, firstName, nameLength);
245
312
  newParent[nameLength] = '\0';
246
313
  result = constructObject(root,
247
- newParent,
248
- first,
249
- createHashtable,
250
- maxProperties,
251
- properties,
252
- propertiesLength,
253
- midIndex,
254
- sidIndex,
255
- next);
314
+ newParent,
315
+ first,
316
+ layout,
317
+ jo,
318
+ next);
256
319
  if (result != RULES_OK) {
257
320
  return result;
258
321
  }
@@ -269,7 +332,7 @@ unsigned int constructObject(char *root,
269
332
  property->name[parentNameLength] = '.';
270
333
  strncpy(&property->name[parentNameLength + 1], firstName, nameLength);
271
334
  property->nameLength = fullNameLength;
272
- property->hash = djbHash(property->name, fullNameLength);
335
+ property->hash = fnv1Hash32(property->name, fullNameLength);
273
336
  } else {
274
337
  #ifdef _WIN32
275
338
  char *fullName = (char *)_alloca(sizeof(char)*(fullNameLength + 1));
@@ -281,15 +344,11 @@ unsigned int constructObject(char *root,
281
344
  strncpy(&fullName[parentNameLength + 1], firstName, nameLength);
282
345
  fullName[fullNameLength] = '\0';
283
346
  result = constructObject(root,
284
- fullName,
285
- first,
286
- createHashtable,
287
- maxProperties,
288
- properties,
289
- propertiesLength,
290
- midIndex,
291
- sidIndex,
292
- next);
347
+ fullName,
348
+ first,
349
+ layout,
350
+ jo,
351
+ next);
293
352
  if (result != RULES_OK) {
294
353
  return result;
295
354
  }
@@ -300,15 +359,20 @@ unsigned int constructObject(char *root,
300
359
  result = readNextName(last, &firstName, &lastName, &hash);
301
360
  }
302
361
 
362
+ if (!parentName) {
363
+ int idResult = fixupIds(jo);
364
+ if (idResult != RULES_OK) {
365
+ return idResult;
366
+ }
367
+ }
368
+
303
369
  return (result == PARSE_END ? RULES_OK: result);
304
370
  }
305
371
 
306
372
  void rehydrateProperty(jsonProperty *property, char *state) {
307
- // ID and SID are treated as strings regardless of type
308
- // to avoid unnecessary conversions
309
- if (!property->isMaterial && property->hash != HASH_ID && property->hash != HASH_SID) {
373
+ if (!property->isMaterial) {
310
374
  unsigned short propertyLength = property->valueLength + 1;
311
- char *propertyFirst = state + property->valueOffset;
375
+ char *propertyFirst = property->valueString;
312
376
  unsigned char propertyType = property->type;
313
377
  unsigned char b = 0;
314
378
  char temp;
@@ -343,7 +407,7 @@ static unsigned int resolveBindingAndEntry(ruleset *tree,
343
407
  char *sid,
344
408
  stateEntry **entry,
345
409
  void **rulesBinding) {
346
- unsigned int sidHash = djbHash(sid, strlen(sid));
410
+ unsigned int sidHash = fnv1Hash32(sid, strlen(sid));
347
411
  if (!ensureEntry(tree, sid, sidHash, entry)) {
348
412
  unsigned int result = getBindingIndex(tree, sidHash, &(*entry)->bindingIndex);
349
413
  if (result != RULES_OK) {
@@ -386,20 +450,14 @@ unsigned int refreshState(void *handle,
386
450
  return result;
387
451
  }
388
452
 
389
- memset(entry->properties, 0, MAX_STATE_PROPERTIES * sizeof(jsonProperty));
390
- entry->propertiesLength = 0;
453
+ memset(entry->jo.properties, 0, MAX_OBJECT_PROPERTIES * sizeof(jsonProperty));
454
+ entry->jo.propertiesLength = 0;
391
455
  char *next;
392
- unsigned int midIndex = UNDEFINED_INDEX;
393
- unsigned int sidIndex = UNDEFINED_INDEX;
394
456
  result = constructObject(entry->state,
395
457
  NULL,
396
458
  NULL,
397
- 1,
398
- MAX_STATE_PROPERTIES,
399
- entry->properties,
400
- &entry->propertiesLength,
401
- &midIndex,
402
- &sidIndex,
459
+ JSON_OBJECT_HASHED,
460
+ &entry->jo,
403
461
  &next);
404
462
  if (result != RULES_OK) {
405
463
  return result;
@@ -416,7 +474,7 @@ unsigned int fetchStateProperty(void *tree,
416
474
  unsigned char ignoreStaleState,
417
475
  char **state,
418
476
  jsonProperty **property) {
419
- unsigned int sidHash = djbHash(sid, strlen(sid));
477
+ unsigned int sidHash = fnv1Hash32(sid, strlen(sid));
420
478
  stateEntry *entry = getEntry(tree, sid, sidHash);
421
479
  if (entry == NULL || entry->lastRefresh == 0) {
422
480
  return ERR_STATE_NOT_LOADED;
@@ -426,11 +484,11 @@ unsigned int fetchStateProperty(void *tree,
426
484
  return ERR_STALE_STATE;
427
485
  }
428
486
 
429
- unsigned int propertyIndex = propertyHash % MAX_STATE_PROPERTIES;
430
- jsonProperty *result = &entry->properties[propertyIndex];
487
+ unsigned int propertyIndex = propertyHash % MAX_OBJECT_PROPERTIES;
488
+ jsonProperty *result = &entry->jo.properties[propertyIndex];
431
489
  while (result->type != 0 && result->hash != propertyHash) {
432
- propertyIndex = (propertyIndex + 1) % MAX_STATE_PROPERTIES;
433
- result = &entry->properties[propertyIndex];
490
+ propertyIndex = (propertyIndex + 1) % MAX_OBJECT_PROPERTIES;
491
+ result = &entry->jo.properties[propertyIndex];
434
492
  }
435
493
 
436
494
  if (!result->type) {