durable_rules 0.34.29 → 0.34.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/src/rules/events.c +69 -154
- data/src/rules/json.c +7 -3
- data/src/rules/json.h +3 -0
- data/src/rules/net.c +72 -55
- data/src/rules/net.h +3 -4
- data/src/rules/rete.c +29 -43
- data/src/rules/state.c +138 -80
- data/src/rules/state.h +29 -13
- metadata +2 -2
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 =
|
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
|
420
|
+
currentHash ^= (*start);
|
421
|
+
currentHash *= FNV_32_PRIME;
|
421
422
|
break;
|
422
423
|
case ST_STRING_ESC:
|
423
424
|
state = ST_STRING_PARSE;
|
424
|
-
|
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
|
-
|
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
|
-
"
|
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 =
|
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
|
721
|
-
"
|
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
|
725
|
-
" if
|
726
|
-
"
|
727
|
-
"
|
728
|
-
"
|
729
|
-
"
|
730
|
-
" if
|
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 =
|
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 =
|
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 =
|
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(\"
|
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
|
2099
|
-
" if
|
2100
|
-
"
|
2101
|
-
"
|
2102
|
-
"
|
2103
|
-
"
|
2104
|
-
"
|
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
|
-
|
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] =
|
2408
|
-
argvl[offset + i * 3] =
|
2409
|
-
argv[offset + i * 3 + 1] =
|
2410
|
-
if (
|
2411
|
-
argvl[offset + i * 3 + 1] =
|
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] =
|
2427
|
+
argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
|
2414
2428
|
}
|
2415
2429
|
|
2416
|
-
switch(
|
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
|
-
|
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*)*(
|
2460
|
-
size_t *argvl = (size_t *)_alloca(sizeof(size_t)*(
|
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[
|
2464
|
-
size_t argvl[
|
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] =
|
2478
|
-
argvl[5] =
|
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[
|
2482
|
-
argvl[
|
2498
|
+
argv[7 + i] = keys[i];
|
2499
|
+
argvl[7 + i] = strlen(keys[i]);
|
2483
2500
|
}
|
2484
2501
|
|
2485
|
-
unsigned int offset =
|
2502
|
+
unsigned int offset = 7 + keysLength;
|
2486
2503
|
for (unsigned int i = 0; i < propertiesLength; ++i) {
|
2487
|
-
argv[offset + i * 3] =
|
2488
|
-
argvl[offset + i * 3] =
|
2489
|
-
argv[offset + i * 3 + 1] =
|
2490
|
-
if (
|
2491
|
-
argvl[offset + i * 3 + 1] =
|
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] =
|
2510
|
+
argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
|
2494
2511
|
}
|
2495
2512
|
|
2496
|
-
switch(
|
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
|
-
|
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
|
-
|
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
|
12
|
-
#define HASH_ANY
|
13
|
-
#define HASH_PRI
|
14
|
-
#define HASH_COUNT
|
15
|
-
#define
|
16
|
-
#define
|
17
|
-
#define
|
18
|
-
#define
|
19
|
-
#define
|
20
|
-
#define
|
21
|
-
#define
|
22
|
-
#define
|
23
|
-
#define
|
24
|
-
#define
|
25
|
-
#define
|
26
|
-
#define
|
27
|
-
#define
|
28
|
-
#define
|
29
|
-
#define
|
30
|
-
#define
|
31
|
-
#define
|
32
|
-
#define
|
33
|
-
#define
|
34
|
-
#define
|
35
|
-
#define
|
36
|
-
#define
|
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 (
|
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 !=
|
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 =
|
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
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
171
|
-
|
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
|
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
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
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
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
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->
|
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
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
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 =
|
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
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
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
|
-
|
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 =
|
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 =
|
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,
|
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
|
-
|
398
|
-
|
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 =
|
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 %
|
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) %
|
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) {
|