durable_rules 0.34.02 → 0.34.03

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6180a0278ca667dd708b04c45359d7d205bb5ee
4
- data.tar.gz: 77f98579d75d5a6ede0cf04de0cb030eb75227cd
3
+ metadata.gz: e2140bced1252c9b280451f9fc98d586b88af859
4
+ data.tar.gz: 28c6962e51f7d51d22f26aaa374c5f079e46a91c
5
5
  SHA512:
6
- metadata.gz: 83a19d52b25b82a7369a679d5223b8e3dc2eb848b0c3a9cc4a75882f327f55434fc7a822bc9f2f91387977f8372daebbb19303cc6223516b67011229aebb172a
7
- data.tar.gz: 0ec42e6ec72b8e569f632bcdb487787eb9692401c556071393ed2b62cccc46d4064f89d76b72f36c9567c2413eeb796fa03ecfc1cf9506493a5224c20d75bd09
6
+ metadata.gz: c462a03d557ec58f26df72d5c81b6f3026348fa606f75590882a29ef35a4da226337aebff6315695e27dac7d4251937497a7eac778822972ce70a375cfe868bd
7
+ data.tar.gz: 229e8f7d619835b4c9902f764798b7099fbf0ebe6c5442c36fd4f5aca136a0be488b65c187273dbf2f18b14e88ff821ef48007499fa41a67e71145f19feb8c3f
data/librb/engine.rb CHANGED
@@ -40,7 +40,7 @@ module Engine
40
40
  end
41
41
 
42
42
  class Closure
43
- attr_reader :host, :handle, :ruleset_name, :_timers, :_cancelled_timers, :_branches, :_messages, :_queues, :_facts, :_retract
43
+ attr_reader :host, :handle, :ruleset_name, :_timers, :_cancelled_timers, :_branches, :_messages, :_queues, :_facts, :_retract, :_deletes, :_deleted
44
44
  attr_accessor :s
45
45
 
46
46
  def initialize(host, state, message, handle, ruleset_name)
@@ -52,11 +52,13 @@ module Engine
52
52
  @_cancelled_timers = {}
53
53
  @_messages = {}
54
54
  @_queues = {}
55
+ @_deletes = {}
55
56
  @_branches = {}
56
57
  @_facts = {}
57
58
  @_retract = {}
58
59
  @_start_time = Time.now
59
60
  @_completed = false
61
+ @_deleted = false
60
62
  if message.kind_of? Hash
61
63
  @m = message
62
64
  else
@@ -93,6 +95,28 @@ module Engine
93
95
  message_list << message
94
96
  end
95
97
 
98
+ def delete(ruleset_name = nil, sid = nil)
99
+ if !ruleset_name
100
+ ruleset_name = @ruleset_name
101
+ end
102
+
103
+ if !sid
104
+ sid = @s.sid
105
+ end
106
+
107
+ if (ruleset_name == @ruleset_name) && (sid == @s.sid)
108
+ @_deleted = true
109
+ end
110
+
111
+ sid_list = []
112
+ if @_deletes.key? ruleset_name
113
+ sid_list = @_deletes[ruleset_name]
114
+ else
115
+ @_deletes[ruleset_name] = sid_list
116
+ end
117
+ sid_list << sid
118
+ end
119
+
96
120
  def get_queue(ruleset_name)
97
121
  if !@_queues.key? ruleset_name
98
122
  @_queues[ruleset_name] = Closure_Queue.new
@@ -479,6 +503,10 @@ module Engine
479
503
  JSON.parse Rules.get_state(@handle, sid.to_s)
480
504
  end
481
505
 
506
+ def delete_state(sid)
507
+ Rules.delete_state(@handle, sid.to_s)
508
+ end
509
+
482
510
  def renew_action_lease(sid)
483
511
  Rules.renew_action_lease @handle, sid.to_s
484
512
  end
@@ -588,6 +616,10 @@ module Engine
588
616
  end
589
617
  end
590
618
 
619
+ for ruleset_name, sid in c._deletes do
620
+ @host.delete_state ruleset_name, sid
621
+ end
622
+
591
623
  binding = 0
592
624
  replies = 0
593
625
  pending = {action_binding => 0}
@@ -656,6 +688,15 @@ module Engine
656
688
  puts e.backtrace
657
689
  complete.call e
658
690
  end
691
+
692
+ if c._deleted
693
+ begin
694
+ delete_state c.s.sid
695
+ rescue Exception => e
696
+ complete.call e
697
+ end
698
+ end
699
+
659
700
  end
660
701
  }
661
702
  result_container[:async] = true
@@ -1073,6 +1114,10 @@ module Engine
1073
1114
  get_ruleset(ruleset_name).get_state sid
1074
1115
  end
1075
1116
 
1117
+ def delete_state(ruleset_name, sid)
1118
+ get_ruleset(ruleset_name).delete_state sid
1119
+ end
1120
+
1076
1121
  def post_batch(ruleset_name, *events)
1077
1122
  get_ruleset(ruleset_name).assert_events events
1078
1123
  end
data/src/rules/json.c CHANGED
@@ -177,6 +177,15 @@ static unsigned int getValue(char *start, char **first, char **last, unsigned ch
177
177
  } else {
178
178
  return ERR_PARSE_STRING;
179
179
  }
180
+ } else if (start[0] == 'n') {
181
+ if (strncmp(start, "null", 4) == 0) {
182
+ *first = start;
183
+ *last = start + 3;
184
+ *type = JSON_NIL;
185
+ return PARSE_OK;
186
+ } else {
187
+ return ERR_PARSE_STRING;
188
+ }
180
189
  } else if (start[0] == '{') {
181
190
  *type = JSON_OBJECT;
182
191
  unsigned int result = getObject(start, first, last);
data/src/rules/net.c CHANGED
@@ -104,6 +104,7 @@ static unsigned int createIdiom(ruleset *tree, jsonValue *newValue, char **idiom
104
104
  if (asprintf(idiomString, "%g", newValue->value.d) == -1) {
105
105
  return ERR_OUT_OF_MEMORY;
106
106
  }
107
+ break;
107
108
  case JSON_BOOL:
108
109
  if (newValue->value.b == 0) {
109
110
  if (asprintf(idiomString, "false") == -1) {
@@ -304,7 +305,8 @@ static unsigned int createTest(ruleset *tree, expression *expr, char **test, cha
304
305
  return RULES_OK;
305
306
  }
306
307
 
307
- static unsigned int loadPartitionCommand(ruleset *tree, binding *rulesBinding, char *name) {
308
+ static unsigned int loadPartitionCommand(ruleset *tree, binding *rulesBinding) {
309
+ char *name = &tree->stringPool[tree->nameOffset];
308
310
  redisContext *reContext = rulesBinding->reContext;
309
311
  redisReply *reply;
310
312
  char *lua = NULL;
@@ -335,7 +337,8 @@ static unsigned int loadPartitionCommand(ruleset *tree, binding *rulesBinding, c
335
337
  return RULES_OK;
336
338
  }
337
339
 
338
- static unsigned int loadRemoveActionCommand(ruleset *tree, binding *rulesBinding, char *name) {
340
+ static unsigned int loadRemoveActionCommand(ruleset *tree, binding *rulesBinding) {
341
+ char *name = &tree->stringPool[tree->nameOffset];
339
342
  redisContext *reContext = rulesBinding->reContext;
340
343
  redisReply *reply;
341
344
  char *lua = NULL;
@@ -386,7 +389,8 @@ static unsigned int loadRemoveActionCommand(ruleset *tree, binding *rulesBinding
386
389
  return RULES_OK;
387
390
  }
388
391
 
389
- static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding, char *name) {
392
+ static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding) {
393
+ char *name = &tree->stringPool[tree->nameOffset];
390
394
  redisContext *reContext = rulesBinding->reContext;
391
395
  redisReply *reply;
392
396
  char *lua = NULL;
@@ -419,7 +423,8 @@ static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding, char
419
423
  return RULES_OK;
420
424
  }
421
425
 
422
- static unsigned int loadUpdateActionCommand(ruleset *tree, binding *rulesBinding, char *name) {
426
+ static unsigned int loadUpdateActionCommand(ruleset *tree, binding *rulesBinding) {
427
+ char *name = &tree->stringPool[tree->nameOffset];
423
428
  redisContext *reContext = rulesBinding->reContext;
424
429
  redisReply *reply;
425
430
  char *lua = NULL;
@@ -448,212 +453,137 @@ static unsigned int loadUpdateActionCommand(ruleset *tree, binding *rulesBinding
448
453
  return RULES_OK;
449
454
  }
450
455
 
451
- static unsigned int setNames(ruleset *tree, binding *rulesBinding, char *name) {
452
- int nameLength = strlen(name);
453
- char *sessionHashset = malloc((nameLength + 3) * sizeof(char));
454
- if (!sessionHashset) {
456
+ static unsigned int loadDeleteSessionCommand(ruleset *tree, binding *rulesBinding) {
457
+ char *name = &tree->stringPool[tree->nameOffset];
458
+ redisContext *reContext = rulesBinding->reContext;
459
+ redisReply *reply;
460
+ char *lua = NULL;
461
+ char *deleteSessionLua = NULL;
462
+ deleteSessionLua = (char*)calloc(1, sizeof(char));
463
+ if (!deleteSessionLua) {
455
464
  return ERR_OUT_OF_MEMORY;
456
465
  }
457
466
 
458
- strncpy(sessionHashset, name, nameLength);
459
- sessionHashset[nameLength] = '!';
460
- sessionHashset[nameLength + 1] = 's';
461
- sessionHashset[nameLength + 2] = '\0';
462
- rulesBinding->sessionHashset = sessionHashset;
467
+ for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
468
+ node *currentNode = &tree->nodePool[i];
469
+
470
+ if (currentNode->type == NODE_ACTION) {
471
+ char *actionName = &tree->stringPool[currentNode->nameOffset];
472
+ char *oldDeleteSessionLua = NULL;
473
+ for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
474
+ unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
475
+ join *currentJoin = &tree->joinPool[currentJoinOffset];
463
476
 
464
- char *factsHashset = malloc((nameLength + 3) * sizeof(char));
465
- if (!factsHashset) {
466
- return ERR_OUT_OF_MEMORY;
467
- }
477
+ oldDeleteSessionLua = deleteSessionLua;
478
+ if (asprintf(&deleteSessionLua,
479
+ "%sredis.call(\"del\", \"%s!%d!r!\" .. sid)\n"
480
+ "redis.call(\"del\", \"%s!%d!r!\" .. sid .. \"!d\")\n",
481
+ deleteSessionLua,
482
+ actionName,
483
+ ii,
484
+ actionName,
485
+ ii) == -1) {
486
+ return ERR_OUT_OF_MEMORY;
487
+ }
488
+ free(oldDeleteSessionLua);
468
489
 
469
- strncpy(factsHashset, name, nameLength);
470
- factsHashset[nameLength] = '!';
471
- factsHashset[nameLength + 1] = 'f';
472
- factsHashset[nameLength + 2] = '\0';
473
- rulesBinding->factsHashset = factsHashset;
490
+ for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
491
+ unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
492
+ expression *expr = &tree->expressionPool[expressionOffset];
493
+ char *currentKey = &tree->stringPool[expr->nameOffset];
474
494
 
475
- char *eventsHashset = malloc((nameLength + 3) * sizeof(char));
476
- if (!eventsHashset) {
477
- return ERR_OUT_OF_MEMORY;
495
+ oldDeleteSessionLua = deleteSessionLua;
496
+ if (asprintf(&deleteSessionLua,
497
+ "%sdelete_message_keys(\"%s!f!\" .. sid)\n"
498
+ "delete_message_keys(\"%s!e!\" .. sid)\n"
499
+ "delete_closure_keys(\"%s!c!\" .. sid)\n"
500
+ "delete_closure_keys(\"%s!i!\" .. sid)\n",
501
+ deleteSessionLua,
502
+ currentKey,
503
+ currentKey,
504
+ currentKey,
505
+ currentKey) == -1) {
506
+ return ERR_OUT_OF_MEMORY;
507
+ }
508
+ free(oldDeleteSessionLua);
509
+ }
510
+ }
511
+ }
478
512
  }
479
513
 
480
- strncpy(eventsHashset, name, nameLength);
481
- eventsHashset[nameLength] = '!';
482
- eventsHashset[nameLength + 1] = 'e';
483
- eventsHashset[nameLength + 2] = '\0';
484
- rulesBinding->eventsHashset = eventsHashset;
485
514
 
486
- char *timersSortedset = malloc((nameLength + 3) * sizeof(char));
487
- if (!timersSortedset) {
515
+ if (asprintf(&lua,
516
+ "local sid = ARGV[1]\n"
517
+ "local delete_message_keys = function(events_key)\n"
518
+ " local all_keys = redis.call(\"keys\", events_key .. \"!m!*\")\n"
519
+ " for i = 1, #all_keys, 1 do\n"
520
+ " redis.call(\"del\", all_keys[i])\n"
521
+ " end\n"
522
+ " redis.call(\"del\", events_key)\n"
523
+ "end\n"
524
+ "local delete_closure_keys = function(closure_key)\n"
525
+ " local all_keys = redis.call(\"keys\", closure_key .. \"!*\")\n"
526
+ " for i = 1, #all_keys, 1 do\n"
527
+ " redis.call(\"del\", all_keys[i])\n"
528
+ " end\n"
529
+ "end\n"
530
+ "redis.call(\"hdel\", \"%s!s\", sid)\n"
531
+ "redis.call(\"zrem\", \"%s!a\", sid)\n"
532
+ "redis.call(\"del\", \"%s!a!\" .. sid)\n"
533
+ "redis.call(\"del\", \"%s!e!\" .. sid)\n"
534
+ "redis.call(\"del\", \"%s!f!\" .. sid)\n"
535
+ "redis.call(\"del\", \"%s!v!\" .. sid)\n%s",
536
+ name,
537
+ name,
538
+ name,
539
+ name,
540
+ name,
541
+ name,
542
+ deleteSessionLua) == -1) {
488
543
  return ERR_OUT_OF_MEMORY;
489
544
  }
490
545
 
491
- strncpy(timersSortedset, name, nameLength);
492
- timersSortedset[nameLength] = '!';
493
- timersSortedset[nameLength + 1] = 't';
494
- timersSortedset[nameLength + 2] = '\0';
495
- rulesBinding->timersSortedset = timersSortedset;
496
- return RULES_OK;
497
- }
498
-
499
- static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
500
- char *name = &tree->stringPool[tree->nameOffset];
501
- int nameLength = strlen(name);
502
- unsigned int result = loadPartitionCommand(tree, rulesBinding, name);
503
- if (result != RULES_OK) {
504
- return result;
505
- }
506
-
507
- // client queues have no commands to load,
508
- if (!tree->stringPool) {
509
- return RULES_OK;
510
- }
511
-
512
- result = loadRemoveActionCommand(tree, rulesBinding, name);
513
- if (result != RULES_OK) {
514
- return result;
515
- }
516
-
517
- result = loadTimerCommand(tree, rulesBinding, name);
518
- if (result != RULES_OK) {
519
- return result;
520
- }
521
-
522
- result = loadUpdateActionCommand(tree, rulesBinding, name);
523
- if (result != RULES_OK) {
524
- return result;
546
+ free(deleteSessionLua);
547
+ redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
548
+ redisGetReply(reContext, (void**)&reply);
549
+ if (reply->type == REDIS_REPLY_ERROR) {
550
+ printf("%s\n", reply->str);
551
+ freeReplyObject(reply);
552
+ free(lua);
553
+ return ERR_REDIS_ERROR;
525
554
  }
526
555
 
527
- result = setNames(tree, rulesBinding, name);
528
- if (result != RULES_OK) {
529
- return result;
530
- }
556
+ strncpy(rulesBinding->deleteSessionHash, reply->str, 40);
557
+ rulesBinding->deleteSessionHash[40] = '\0';
558
+ freeReplyObject(reply);
559
+ free(lua);
560
+ return RULES_OK;
531
561
 
562
+ }
563
+ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding) {
564
+ char *name = &tree->stringPool[tree->nameOffset];
532
565
  redisContext *reContext = rulesBinding->reContext;
533
566
  redisReply *reply;
534
- #ifdef _WIN32
535
- char *actionKey = (char *)_alloca(sizeof(char)*(nameLength + 3));
536
- sprintf_s(actionKey, nameLength + 3, "%s!a", name);
537
- #else
538
- char actionKey[nameLength + 3];
539
- snprintf(actionKey, nameLength + 3, "%s!a", name);
540
- #endif
541
567
  char *lua = NULL;
542
- char *peekActionLua = NULL;
543
568
  char *addMessageLua = NULL;
544
- char *oldLua;
545
-
546
- peekActionLua = (char*)calloc(1, sizeof(char));
547
- if (!peekActionLua) {
548
- return ERR_OUT_OF_MEMORY;
549
- }
550
-
551
- lua = (char*)calloc(1, sizeof(char));
552
- if (!lua) {
553
- return ERR_OUT_OF_MEMORY;
554
- }
555
-
556
569
  addMessageLua = (char*)calloc(1, sizeof(char));
557
570
  if (!addMessageLua) {
558
571
  return ERR_OUT_OF_MEMORY;
559
572
  }
560
573
 
561
574
  for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
562
- char *oldPeekActionLua;
563
575
  node *currentNode = &tree->nodePool[i];
564
576
 
565
577
  if (currentNode->type == NODE_ACTION) {
566
- char *packFrameLua = NULL;
567
- char *unpackFrameLua = NULL;
568
- char *oldPackFrameLua = NULL;
569
- char *oldUnpackFrameLua = NULL;
570
578
  char *oldAddMessageLua = NULL;
571
- char *actionName = &tree->stringPool[currentNode->nameOffset];
572
- char *actionLastName = strchr(actionName, '!');
573
- #ifdef _WIN32
574
- char *actionAlias = (char *)_alloca(sizeof(char)*(actionLastName - actionName + 1));
575
- #else
576
- char actionAlias[actionLastName - actionName + 1];
577
- #endif
578
-
579
- strncpy(actionAlias, actionName, actionLastName - actionName);
580
- actionAlias[actionLastName - actionName] = '\0';
581
-
582
579
  for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
583
580
  unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
584
581
  join *currentJoin = &tree->joinPool[currentJoinOffset];
585
-
586
- oldPeekActionLua = peekActionLua;
587
- if (asprintf(&peekActionLua,
588
- "%sif input_keys[\"%s!%d!r!\"] then\n"
589
- "local context = {}\n"
590
- "context_directory[\"%s!%d!r!\"] = context\n"
591
- "reviewers = {}\n"
592
- "context[\"reviewers\"] = reviewers\n"
593
- "keys = {}\n"
594
- "context[\"keys\"] = keys\n"
595
- "primary_frame_keys = {}\n"
596
- "context[\"primary_frame_keys\"] = primary_frame_keys\n",
597
- peekActionLua,
598
- actionName,
599
- ii,
600
- actionName,
601
- ii) == -1) {
602
- return ERR_OUT_OF_MEMORY;
603
- }
604
- free(oldPeekActionLua);
605
-
606
- oldLua = lua;
607
- if (asprintf(&lua,
608
- "%stoggle = false\n"
609
- "context = {}\n"
610
- "reviewers = {}\n"
611
- "context[\"reviewers\"] = reviewers\n"
612
- "frame_packers = {}\n"
613
- "context[\"frame_packers\"] = frame_packers\n"
614
- "frame_unpackers = {}\n"
615
- "context[\"frame_unpackers\"] = frame_unpackers\n"
616
- "primary_message_keys = {}\n"
617
- "context[\"primary_message_keys\"] = primary_message_keys\n"
618
- "primary_frame_keys = {}\n"
619
- "context[\"primary_frame_keys\"] = primary_frame_keys\n"
620
- "keys = {}\n"
621
- "context[\"keys\"] = keys\n"
622
- "inverse_directory = {}\n"
623
- "context[\"inverse_directory\"] = inverse_directory\n"
624
- "directory = {[\"0\"] = 1}\n"
625
- "context[\"directory\"] = directory\n"
626
- "context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
627
- "context[\"expressions_count\"] = %d\n",
628
- lua,
629
- actionName,
630
- ii,
631
- currentJoin->expressionsLength) == -1) {
632
- return ERR_OUT_OF_MEMORY;
633
- }
634
- free(oldLua);
635
582
 
636
583
  for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
637
584
  unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
638
585
  expression *expr = &tree->expressionPool[expressionOffset];
639
- char *currentAlias = &tree->stringPool[expr->aliasOffset];
640
586
  char *currentKey = &tree->stringPool[expr->nameOffset];
641
- char *nextKeyTest;
642
- if (iii == (currentJoin->expressionsLength - 1)) {
643
- nextKeyTest = (char*)calloc(1, sizeof(char));
644
- if (!nextKeyTest) {
645
- return ERR_OUT_OF_MEMORY;
646
- }
647
- } else {
648
- unsigned int nextExpressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii + 1];
649
- expression *nextExpr = &tree->expressionPool[nextExpressionOffset];
650
- if (asprintf(&nextKeyTest,
651
- "or input_keys[\"%s\"]",
652
- &tree->stringPool[nextExpr->nameOffset]) == -1) {
653
- return ERR_OUT_OF_MEMORY;
654
- }
655
- }
656
-
657
587
  if (iii == 0) {
658
588
  oldAddMessageLua = addMessageLua;
659
589
  if (!addMessageLua) {
@@ -672,62 +602,175 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
672
602
  return ERR_OUT_OF_MEMORY;
673
603
  }
674
604
  free(oldAddMessageLua);
605
+ } else {
606
+ char *test = NULL;
607
+ char *primaryKeyLua = NULL;
608
+ char *primaryFrameKeyLua = NULL;
609
+ unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
610
+ if (result != RULES_OK) {
611
+ return result;
612
+ }
675
613
 
676
- if (expr->not) {
677
- if (asprintf(&packFrameLua,
678
- " result[1] = \"$n\"\n") == -1) {
679
- return ERR_OUT_OF_MEMORY;
680
- }
614
+ oldAddMessageLua = addMessageLua;
615
+ if (asprintf(&addMessageLua,
616
+ "%sif input_keys[\"%s\"] then\n"
617
+ " primary_message_keys[\"%s\"] = function(message)\n"
618
+ " local result = \"\"\n%s"
619
+ " return result\n"
620
+ " end\n"
621
+ "end\n",
622
+ addMessageLua,
623
+ currentKey,
624
+ currentKey,
625
+ primaryKeyLua) == -1) {
626
+ return ERR_OUT_OF_MEMORY;
627
+ }
628
+ free(oldAddMessageLua);
629
+ free(test);
630
+ free(primaryKeyLua);
631
+ free(primaryFrameKeyLua);
632
+ }
633
+ }
634
+ }
635
+ }
636
+ }
681
637
 
682
- if (asprintf(&unpackFrameLua,
683
- " result[\"%s\"] = \"$n\"\n",
684
- currentAlias) == -1) {
685
- return ERR_OUT_OF_MEMORY;
686
- }
687
-
688
- oldLua = lua;
689
- if (asprintf(&lua,
690
- "%sif input_keys[\"%s\"] %s then\n"
691
- " toggle = true\n"
692
- " context_directory[\"%s\"] = context\n"
693
- " keys[1] = \"%s\"\n"
694
- " inverse_directory[1] = true\n"
695
- " directory[\"%s\"] = 1\n"
696
- " reviewers[1] = function(message, frame, index)\n"
697
- " if not message then\n"
698
- " frame[\"%s\"] = \"$n\"\n"
699
- " return true\n"
638
+ if (asprintf(&lua,
639
+ "local sid = ARGV[1]\n"
640
+ "local assert_fact = tonumber(ARGV[2])\n"
641
+ "local keys_count = tonumber(ARGV[3])\n"
642
+ "local events_hashset = \"%s!e!\" .. sid\n"
643
+ "local facts_hashset = \"%s!f!\" .. sid\n"
644
+ "local visited_hashset = \"%s!v!\" .. sid\n"
645
+ "local message = {}\n"
646
+ "local primary_message_keys = {}\n"
647
+ "local input_keys = {}\n"
648
+ "local save_message = function(current_key, message, events_key, messages_key)\n"
649
+ " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
650
+ " local primary_key = primary_message_keys[current_key](message)\n"
651
+ " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
652
+ "end\n"
653
+ "for index = 4 + keys_count, #ARGV, 3 do\n"
654
+ " if ARGV[index + 2] == \"1\" then\n"
655
+ " message[ARGV[index]] = ARGV[index + 1]\n"
656
+ " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
657
+ " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
658
+ " elseif ARGV[index + 2] == \"4\" then\n"
659
+ " if ARGV[index + 1] == \"true\" then\n"
660
+ " message[ARGV[index]] = true\n"
661
+ " else\n"
662
+ " message[ARGV[index]] = false\n"
700
663
  " end\n"
701
- " return false\n"
702
- " end\n"
703
- " frame_packers[1] = function(frame, full_encode)\n"
704
- " local result = {}\n%s"
705
- " return cmsgpack.pack(result)\n"
706
664
  " end\n"
707
- " frame_unpackers[1] = function(packed_frame)\n"
708
- " local frame = cmsgpack.unpack(packed_frame)\n"
709
- " local result = {}\n%s"
710
- " return result\n"
665
+ "end\n"
666
+ "local mid = message[\"id\"]\n"
667
+ "if redis.call(\"hsetnx\", visited_hashset, message[\"id\"], 1) == 0 then\n"
668
+ " if assert_fact == 0 then\n"
669
+ " if not redis.call(\"hget\", events_hashset, mid) then\n"
670
+ " return false\n"
671
+ " end\n"
672
+ " else\n"
673
+ " if not redis.call(\"hget\", facts_hashset, mid) then\n"
674
+ " return false\n"
675
+ " end\n"
711
676
  " end\n"
712
- " primary_message_keys[1] = function(message)\n"
713
- " return \"\"\n"
677
+ "end\n"
678
+ "for index = 4, 3 + keys_count, 1 do\n"
679
+ " input_keys[ARGV[index]] = true\n"
680
+ "end\n"
681
+ "%sif assert_fact == 1 then\n"
682
+ " message[\"$f\"] = 1\n"
683
+ " for index = 4, 3 + keys_count, 1 do\n"
684
+ " local key = ARGV[index]\n"
685
+ " save_message(key, message, key .. \"!f!\" .. sid, facts_hashset)\n"
714
686
  " end\n"
715
- " primary_frame_keys[1] = function(frame)\n"
716
- " return \"\"\n"
687
+ "else\n"
688
+ " for index = 4, 3 + keys_count, 1 do\n"
689
+ " local key = ARGV[index]\n"
690
+ " save_message(key, message, key .. \"!e!\" .. sid, events_hashset)\n"
717
691
  " end\n"
718
692
  "end\n",
719
- lua,
720
- currentKey,
721
- nextKeyTest,
722
- currentKey,
723
- currentKey,
724
- currentKey,
725
- currentAlias,
726
- packFrameLua,
727
- unpackFrameLua) == -1) {
693
+ name,
694
+ name,
695
+ name,
696
+ addMessageLua) == -1) {
697
+ return ERR_OUT_OF_MEMORY;
698
+ }
699
+
700
+ free(addMessageLua);
701
+ redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
702
+ redisGetReply(reContext, (void**)&reply);
703
+ if (reply->type == REDIS_REPLY_ERROR) {
704
+ printf("%s\n", reply->str);
705
+ freeReplyObject(reply);
706
+ free(lua);
707
+ return ERR_REDIS_ERROR;
708
+ }
709
+
710
+ strncpy(rulesBinding->addMessageHash, reply->str, 40);
711
+ rulesBinding->addMessageHash[40] = '\0';
712
+ freeReplyObject(reply);
713
+ free(lua);
714
+ return RULES_OK;
715
+ }
716
+
717
+ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding) {
718
+ char *name = &tree->stringPool[tree->nameOffset];
719
+ redisContext *reContext = rulesBinding->reContext;
720
+ redisReply *reply;
721
+ char *lua = NULL;
722
+
723
+ char *peekActionLua = NULL;
724
+ peekActionLua = (char*)calloc(1, sizeof(char));
725
+ if (!peekActionLua) {
726
+ return ERR_OUT_OF_MEMORY;
727
+ }
728
+
729
+ for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
730
+ char *oldPeekActionLua;
731
+ node *currentNode = &tree->nodePool[i];
732
+
733
+ if (currentNode->type == NODE_ACTION) {
734
+ char *unpackFrameLua = NULL;
735
+ char *oldUnpackFrameLua = NULL;
736
+ char *actionName = &tree->stringPool[currentNode->nameOffset];
737
+ for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
738
+ unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
739
+ join *currentJoin = &tree->joinPool[currentJoinOffset];
740
+
741
+ oldPeekActionLua = peekActionLua;
742
+ if (asprintf(&peekActionLua,
743
+ "%sif input_keys[\"%s!%d!r!\"] then\n"
744
+ "local context = {}\n"
745
+ "context_directory[\"%s!%d!r!\"] = context\n"
746
+ "reviewers = {}\n"
747
+ "context[\"reviewers\"] = reviewers\n"
748
+ "keys = {}\n"
749
+ "context[\"keys\"] = keys\n"
750
+ "primary_frame_keys = {}\n"
751
+ "context[\"primary_frame_keys\"] = primary_frame_keys\n",
752
+ peekActionLua,
753
+ actionName,
754
+ ii,
755
+ actionName,
756
+ ii) == -1) {
757
+ return ERR_OUT_OF_MEMORY;
758
+ }
759
+ free(oldPeekActionLua);
760
+
761
+ for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
762
+ unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
763
+ expression *expr = &tree->expressionPool[expressionOffset];
764
+ char *currentAlias = &tree->stringPool[expr->aliasOffset];
765
+ char *currentKey = &tree->stringPool[expr->nameOffset];
766
+
767
+ if (iii == 0) {
768
+ if (expr->not) {
769
+ if (asprintf(&unpackFrameLua,
770
+ " result[\"%s\"] = \"$n\"\n",
771
+ currentAlias) == -1) {
728
772
  return ERR_OUT_OF_MEMORY;
729
773
  }
730
- free(oldLua);
731
774
 
732
775
  oldPeekActionLua = peekActionLua;
733
776
  if (!peekActionLua) {
@@ -750,19 +793,7 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
750
793
  return ERR_OUT_OF_MEMORY;
751
794
  }
752
795
  free(oldPeekActionLua);
753
- // not (expr->not)
754
796
  } else {
755
- if (asprintf(&packFrameLua,
756
- " message = frame[\"%s\"]\n"
757
- " if full_encode and not message[\"$f\"] then\n"
758
- " result[1] = message\n"
759
- " else\n"
760
- " result[1] = message[\"id\"]\n"
761
- " end\n",
762
- currentAlias) == -1) {
763
- return ERR_OUT_OF_MEMORY;
764
- }
765
-
766
797
  if (asprintf(&unpackFrameLua,
767
798
  " message = fetch_message(frame[1])\n"
768
799
  " if not message then\n"
@@ -773,87 +804,16 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
773
804
  return ERR_OUT_OF_MEMORY;
774
805
  }
775
806
 
776
- oldLua = lua;
777
- if (asprintf(&lua,
778
- "%sif input_keys[\"%s\"] %s then\n"
779
- " toggle = true\n"
780
- " context_directory[\"%s\"] = context\n"
781
- " keys[1] = \"%s\"\n"
782
- " inverse_directory[1] = true\n"
783
- " directory[\"%s\"] = 1\n"
784
- " reviewers[1] = function(message, frame, index)\n"
785
- " if message then\n"
786
- " frame[\"%s\"] = message\n"
787
- " return true\n"
788
- " end\n"
789
- " return false\n"
790
- " end\n"
791
- " frame_packers[1] = function(frame, full_encode)\n"
792
- " local result = {}\n"
793
- " local message\n%s"
794
- " return cmsgpack.pack(result)\n"
795
- " end\n"
796
- " frame_unpackers[1] = function(packed_frame)\n"
797
- " local frame = cmsgpack.unpack(packed_frame)\n"
798
- " local result = {}\n"
799
- " local message\n%s"
800
- " return result\n"
801
- " end\n"
802
- " primary_message_keys[1] = function(message)\n"
803
- " return \"\"\n"
804
- " end\n"
805
- " primary_frame_keys[1] = function(frame)\n"
806
- " return \"\"\n"
807
- " end\n"
808
- "end\n",
809
- lua,
810
- currentKey,
811
- nextKeyTest,
812
- currentKey,
813
- currentKey,
814
- currentKey,
815
- currentAlias,
816
- packFrameLua,
817
- unpackFrameLua) == -1) {
818
- return ERR_OUT_OF_MEMORY;
819
- }
820
- free(oldLua);
821
807
  }
822
- // not (iii == 0)
823
808
  } else {
824
- char *test = NULL;
825
- char *primaryKeyLua = NULL;
826
- char *primaryFrameKeyLua = NULL;
827
- unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
828
- if (result != RULES_OK) {
829
- return result;
830
- }
831
-
832
- oldAddMessageLua = addMessageLua;
833
- if (asprintf(&addMessageLua,
834
- "%sif input_keys[\"%s\"] then\n"
835
- " primary_message_keys[\"%s\"] = function(message)\n"
836
- " local result = \"\"\n%s"
837
- " return result\n"
838
- " end\n"
839
- "end\n",
840
- addMessageLua,
841
- currentKey,
842
- currentKey,
843
- primaryKeyLua) == -1) {
844
- return ERR_OUT_OF_MEMORY;
845
- }
846
- free(oldAddMessageLua);
847
-
848
- if (expr->not) {
849
- oldPackFrameLua = packFrameLua;
850
- if (asprintf(&packFrameLua,
851
- "%s result[%d] = \"$n\"\n",
852
- packFrameLua,
853
- iii + 1) == -1) {
854
- return ERR_OUT_OF_MEMORY;
809
+ if (expr->not) {
810
+ char *test = NULL;
811
+ char *primaryKeyLua = NULL;
812
+ char *primaryFrameKeyLua = NULL;
813
+ unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
814
+ if (result != RULES_OK) {
815
+ return result;
855
816
  }
856
- free(oldPackFrameLua);
857
817
 
858
818
  oldUnpackFrameLua = unpackFrameLua;
859
819
  if (asprintf(&unpackFrameLua,
@@ -864,64 +824,6 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
864
824
  }
865
825
  free(oldUnpackFrameLua);
866
826
 
867
- oldLua = lua;
868
- if (asprintf(&lua,
869
- "%sif toggle %s then\n"
870
- " toggle = true\n"
871
- " context_directory[\"%s\"] = context\n"
872
- " keys[%d] = \"%s\"\n"
873
- " inverse_directory[%d] = true\n"
874
- " directory[\"%s\"] = %d\n"
875
- " reviewers[%d] = function(message, frame, index)\n"
876
- " if not message or not (%s) then\n"
877
- " frame[\"%s\"] = \"$n\"\n"
878
- " return true\n"
879
- " end\n"
880
- " return false\n"
881
- " end\n"
882
- " frame_packers[%d] = function(frame, full_encode)\n"
883
- " local result = {}\n"
884
- " local message\n%s"
885
- " return cmsgpack.pack(result)\n"
886
- " end\n"
887
- " frame_unpackers[%d] = function(packed_frame)\n"
888
- " local frame = cmsgpack.unpack(packed_frame)\n"
889
- " local result = {}\n"
890
- " local message\n%s"
891
- " return result\n"
892
- " end\n"
893
- " primary_message_keys[%d] = function(message)\n"
894
- " local result = \"\"\n%s"
895
- " return result\n"
896
- " end\n"
897
- " primary_frame_keys[%d] = function(frame)\n"
898
- " local result = \"\"\n%s"
899
- " return result\n"
900
- " end\n"
901
- "end\n",
902
- lua,
903
- nextKeyTest,
904
- currentKey,
905
- iii + 1,
906
- currentKey,
907
- iii + 1,
908
- currentKey,
909
- iii + 1,
910
- iii + 1,
911
- test,
912
- currentAlias,
913
- iii + 1,
914
- packFrameLua,
915
- iii + 1,
916
- unpackFrameLua,
917
- iii + 1,
918
- primaryKeyLua,
919
- iii + 1,
920
- primaryFrameKeyLua) == -1) {
921
- return ERR_OUT_OF_MEMORY;
922
- }
923
- free(oldLua);
924
-
925
827
  oldPeekActionLua = peekActionLua;
926
828
  if (asprintf(&peekActionLua,
927
829
  "%skeys[%d] = \"%s\"\n"
@@ -945,25 +847,10 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
945
847
  return ERR_OUT_OF_MEMORY;
946
848
  }
947
849
  free(oldPeekActionLua);
948
-
949
- // not (expr->not)
850
+ free(test);
851
+ free(primaryKeyLua);
852
+ free(primaryFrameKeyLua);
950
853
  } else {
951
- oldPackFrameLua = packFrameLua;
952
- if (asprintf(&packFrameLua,
953
- "%s message = frame[\"%s\"]\n"
954
- " if full_encode and not message[\"$f\"] then\n"
955
- " result[%d] = message\n"
956
- " else\n"
957
- " result[%d] = message[\"id\"]\n"
958
- " end\n",
959
- packFrameLua,
960
- currentAlias,
961
- iii + 1,
962
- iii + 1) == -1) {
963
- return ERR_OUT_OF_MEMORY;
964
- }
965
- free(oldPackFrameLua);
966
-
967
854
  oldUnpackFrameLua = unpackFrameLua;
968
855
  if (asprintf(&unpackFrameLua,
969
856
  "%s message = fetch_message(frame[%d])\n"
@@ -977,69 +864,7 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
977
864
  return ERR_OUT_OF_MEMORY;
978
865
  }
979
866
  free(oldUnpackFrameLua);
980
-
981
- oldLua = lua;
982
- if (asprintf(&lua,
983
- "%sif toggle %s then\n"
984
- " toggle = true\n"
985
- " context_directory[\"%s\"] = context\n"
986
- " keys[%d] = \"%s\"\n"
987
- " directory[\"%s\"] = %d\n"
988
- " reviewers[%d] = function(message, frame, index)\n"
989
- " if message and %s then\n"
990
- " frame[\"%s\"] = message\n"
991
- " return true\n"
992
- " end\n"
993
- " return false\n"
994
- " end\n"
995
- " frame_packers[%d] = function(frame, full_encode)\n"
996
- " local result = {}\n"
997
- " local message\n%s"
998
- " return cmsgpack.pack(result)\n"
999
- " end\n"
1000
- " frame_unpackers[%d] = function(packed_frame)\n"
1001
- " local frame = cmsgpack.unpack(packed_frame)\n"
1002
- " local result = {}\n"
1003
- " local message\n%s"
1004
- " return result\n"
1005
- " end\n"
1006
- " primary_message_keys[%d] = function(message)\n"
1007
- " local result = \"\"\n%s"
1008
- " return result\n"
1009
- " end\n"
1010
- " primary_frame_keys[%d] = function(frame)\n"
1011
- " local result = \"\"\n%s"
1012
- " return result\n"
1013
- " end\n"
1014
- "end\n",
1015
- lua,
1016
- nextKeyTest,
1017
- currentKey,
1018
- iii + 1,
1019
- currentKey,
1020
- currentKey,
1021
- iii + 1,
1022
- iii + 1,
1023
- test,
1024
- currentAlias,
1025
- iii + 1,
1026
- packFrameLua,
1027
- iii + 1,
1028
- unpackFrameLua,
1029
- iii + 1,
1030
- primaryKeyLua,
1031
- iii + 1,
1032
- primaryFrameKeyLua) == -1) {
1033
- return ERR_OUT_OF_MEMORY;
1034
- }
1035
- free(oldLua);
1036
- // done not (expr->not)
1037
867
  }
1038
- free(nextKeyTest);
1039
- free(test);
1040
- free(primaryKeyLua);
1041
- free(primaryFrameKeyLua);
1042
- // done not (iii == 0)
1043
868
  }
1044
869
  }
1045
870
 
@@ -1057,103 +882,29 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
1057
882
  }
1058
883
  free(oldPeekActionLua);
1059
884
 
1060
- if (currentNode->value.c.span > 0) {
1061
- oldLua = lua;
1062
- if (asprintf(&lua,
1063
- "%sif toggle then\n"
1064
- " context[\"process_key\"] = process_key_with_span\n"
1065
- " context[\"process_key_count\"] = %d\n"
1066
- "end\n",
1067
- lua,
1068
- currentNode->value.c.span) == -1) {
1069
- return ERR_OUT_OF_MEMORY;
1070
- }
1071
- free(oldLua);
1072
-
1073
- } else if (currentNode->value.c.cap > 0) {
1074
- oldLua = lua;
1075
- if (asprintf(&lua,
1076
- "%sif toggle then\n"
1077
- " context[\"process_key\"] = process_key_with_cap\n"
1078
- " context[\"process_key_count\"] = %d\n"
1079
- "end\n",
1080
- lua,
1081
- currentNode->value.c.cap) == -1) {
1082
- return ERR_OUT_OF_MEMORY;
1083
- }
1084
- free(oldLua);
1085
-
1086
- } else {
1087
- oldLua = lua;
1088
- if (asprintf(&lua,
1089
- "%sif toggle then\n"
1090
- " context[\"process_key\"] = process_key_with_window\n"
1091
- " context[\"process_key_count\"] = %d\n"
1092
- "end\n",
1093
- lua,
1094
- currentNode->value.c.count) == -1) {
1095
- return ERR_OUT_OF_MEMORY;
1096
- }
1097
- free(oldLua);
1098
- }
1099
885
  }
1100
886
 
1101
887
  free(unpackFrameLua);
1102
- free(packFrameLua);
1103
888
  }
1104
889
  }
1105
890
 
1106
- oldLua = lua;
1107
- if (asprintf(&lua,
1108
- "local sid = ARGV[1]\n"
1109
- "local mid = ARGV[2]\n"
1110
- "local score = tonumber(ARGV[3])\n"
1111
- "local assert_fact = tonumber(ARGV[4])\n"
1112
- "local keys_count = tonumber(ARGV[5])\n"
1113
- "local events_hashset = \"%s!e!\" .. sid\n"
1114
- "local facts_hashset = \"%s!f!\" .. sid\n"
1115
- "local visited_hashset = \"%s!v!\" .. sid\n"
1116
- "local actions_key = \"%s!a\"\n"
891
+ if (asprintf(&lua,
892
+ "local facts_key = \"%s!f!\"\n"
893
+ "local events_key = \"%s!e!\"\n"
894
+ "local action_key = \"%s!a\"\n"
1117
895
  "local state_key = \"%s!s\"\n"
1118
- "local queue_action = false\n"
1119
- "local facts_message_cache = {}\n"
1120
- "local events_message_cache = {}\n"
1121
- "local facts_mids_cache = {}\n"
1122
- "local events_mids_cache = {}\n"
896
+ "local timers_key = \"%s!t\"\n"
1123
897
  "local context_directory = {}\n"
1124
- "local input_keys = {}\n"
1125
- "local toggle\n"
1126
- "local expressions_count\n"
1127
- "local results\n"
1128
- "local unpacked_results\n"
1129
- "local context\n"
1130
898
  "local keys\n"
1131
899
  "local reviewers\n"
1132
- "local frame_packers\n"
1133
- "local frame_unpackers\n"
1134
- "local primary_message_keys\n"
1135
900
  "local primary_frame_keys\n"
1136
- "local directory\n"
1137
- "local results_key\n"
1138
- "local inverse_directory\n"
1139
- "local key\n"
1140
- "local cleanup_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1141
- " local event_mids = mids_cache[events_key]\n"
1142
- " local primary_key = primary_frame_keys[index](frame)\n"
1143
- " local new_mids = event_mids[primary_key]\n"
1144
- " local result_mids = {}\n"
1145
- " for i = 1, #new_mids, 1 do\n"
1146
- " local new_mid = new_mids[i]\n"
1147
- " if message_cache[new_mid] ~= false then\n"
1148
- " table.insert(result_mids, new_mid)\n"
1149
- " end\n"
1150
- " end\n"
1151
- " event_mids[primary_key] = result_mids\n"
1152
- " redis.call(\"del\", events_key .. \"!m!\" .. primary_key)\n"
1153
- " for i = 1, #result_mids, 1 do\n"
1154
- " redis.call(\"rpush\", events_key .. \"!m!\" .. primary_key, result_mids[i])\n"
1155
- " end\n"
1156
- "end\n"
901
+ "local facts_hashset\n"
902
+ "local events_hashset\n"
903
+ "local events_message_cache = {}\n"
904
+ "local facts_message_cache = {}\n"
905
+ "local facts_mids_cache = {}\n"
906
+ "local events_mids_cache = {}\n"
907
+ "local get_context\n"
1157
908
  "local get_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1158
909
  " local event_mids = mids_cache[events_key]\n"
1159
910
  " local primary_key = primary_frame_keys[index](frame)\n"
@@ -1185,412 +936,697 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
1185
936
  " return message\n"
1186
937
  "end\n"
1187
938
  "local fetch_message = function(new_mid)\n"
1188
- " local message = get_message(new_mid, events_hashset, events_message_cache)\n"
1189
- " if not message then\n"
1190
- " message = get_message(new_mid, facts_hashset, facts_message_cache)\n"
939
+ " if type(new_mid) == \"table\" then\n"
940
+ " return new_mid\n"
1191
941
  " end\n"
1192
- " return message\n"
1193
- "end\n"
1194
- "local save_message = function(index, message, events_key, messages_key)\n"
1195
- " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
1196
- " local primary_key = primary_message_keys[index](message)\n"
1197
- " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
942
+ " return get_message(new_mid, facts_hashset, facts_message_cache)\n"
1198
943
  "end\n"
1199
- "local save_result = function(frame, index)\n"
1200
- " table.insert(results, 1, frame_packers[index](frame, true))\n"
1201
- " table.insert(unpacked_results, 1, frame)\n"
1202
- " for name, message in pairs(frame) do\n"
1203
- " if message ~= \"$n\" and not message[\"$f\"] then\n"
1204
- " redis.call(\"hdel\", events_hashset, message[\"id\"])\n"
1205
- // message cache always looked up using strings
1206
- " events_message_cache[tostring(message[\"id\"])] = false\n"
944
+ "local validate_frame_for_key = function(packed_frame, frame, index, events_list_key, messages_key, mids_cache, message_cache, sid)\n"
945
+ " local new_mids = get_mids(index, frame, events_list_key, messages_key, mids_cache, message_cache)\n"
946
+ " for i = 1, #new_mids, 1 do\n"
947
+ " local message = get_message(new_mids[i], messages_key, message_cache)\n"
948
+ " if message and not reviewers[index](message, frame, index) then\n"
949
+ " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. new_mids[i]\n"
950
+ " redis.call(\"rpush\", frames_key, packed_frame)\n"
951
+ " return false\n"
1207
952
  " end\n"
1208
953
  " end\n"
954
+ " return true\n"
1209
955
  "end\n"
1210
- "local is_pure_fact = function(frame, index)\n"
1211
- " local message_count = 0\n"
1212
- " for name, message in pairs(frame) do\n"
1213
- " if message ~= 1 and message[\"$f\"] ~= 1 then\n"
1214
- " return false\n"
1215
- " end\n"
1216
- " message_count = message_count + 1\n"
1217
- " end\n"
1218
- " return (message_count == index - 1)\n"
956
+ "local validate_frame = function(packed_frame, frame, index, sid)\n"
957
+ " local first_result = validate_frame_for_key(packed_frame, frame, index, keys[index] .. \"!e!\" .. sid, events_hashset, events_mids_cache, events_message_cache, sid)\n"
958
+ " local second_result = validate_frame_for_key(packed_frame, frame, index, keys[index] ..\"!f!\" .. sid, facts_hashset, facts_mids_cache, facts_message_cache, sid)\n"
959
+ " return first_result and second_result\n"
1219
960
  "end\n"
1220
- "local process_frame\n"
1221
- "local process_event_and_frame = function(message, frame, index, use_facts)\n"
1222
- " local result = 0\n"
1223
- " local new_frame = {}\n"
1224
- " for name, new_message in pairs(frame) do\n"
1225
- " new_frame[name] = new_message\n"
961
+ "local review_frame = function(frame, rule_action_key, sid, max_score)\n"
962
+ " local indexes = {}\n"
963
+ " local action_id = string.sub(rule_action_key, 1, (string.len(sid) + 1) * -1)\n"
964
+ " local context = get_context(action_id)\n"
965
+ " local full_frame = {}\n"
966
+ " local cancel = false\n"
967
+ " events_hashset = events_key .. sid\n"
968
+ " facts_hashset = facts_key .. sid\n"
969
+ " keys = context[\"keys\"]\n"
970
+ " reviewers = context[\"reviewers\"]\n"
971
+ " primary_frame_keys = context[\"primary_frame_keys\"]\n"
972
+ " if not context[\"frame_restore\"](frame, full_frame) then\n"
973
+ " cancel = true\n"
974
+ " else\n"
975
+ " for i = 1, #frame, 1 do\n"
976
+ " if frame[i] == \"$n\" then\n"
977
+ " if not validate_frame(frame, full_frame, i, sid) then\n"
978
+ " cancel = true\n"
979
+ " break\n"
980
+ " end\n"
981
+ " end\n"
982
+ " end\n"
1226
983
  " end\n"
1227
- " if reviewers[index](message, new_frame, index) then\n"
1228
- " if (index == expressions_count) then\n"
1229
- " save_result(new_frame, index)\n"
1230
- " return 1\n"
1231
- " else\n"
1232
- " result = process_frame(new_frame, index + 1, use_facts)\n"
1233
- " if result == 0 or use_facts then\n"
1234
- " local frames_key\n"
1235
- " local primary_key = primary_frame_keys[index + 1](new_frame)\n"
1236
- " frames_key = keys[index + 1] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
1237
- " redis.call(\"rpush\", frames_key, frame_packers[index](new_frame))\n"
984
+ " if cancel then\n"
985
+ " for i = 1, #frame, 1 do\n"
986
+ " if type(frame[i]) == \"table\" then\n"
987
+ " redis.call(\"hsetnx\", events_hashset, frame[i][\"id\"], cmsgpack.pack(frame[i]))\n"
988
+ " redis.call(\"zadd\", timers_key, max_score, \"p:\" .. cjson.encode(frame[i]))\n"
1238
989
  " end\n"
1239
990
  " end\n"
991
+ " full_frame = nil\n"
1240
992
  " end\n"
1241
- " return result\n"
993
+ " return full_frame\n"
1242
994
  "end\n"
1243
- "local process_frame_for_key = function(frame, index, events_key, use_facts)\n"
1244
- " local result = nil\n"
1245
- " local inverse = inverse_directory[index]\n"
1246
- " local messages_key = events_hashset\n"
1247
- " local message_cache = events_message_cache\n"
1248
- " local mids_cache = events_mids_cache\n"
1249
- " local cleanup = false\n"
1250
- " if use_facts then\n"
1251
- " messages_key = facts_hashset\n"
1252
- " message_cache = facts_message_cache\n"
1253
- " mids_cache = facts_mids_cache\n"
995
+ "local load_frame_from_rule = function(rule_action_key, raw_count, sid, max_score)\n"
996
+ " local frames = {}\n"
997
+ " local packed_frames = {}\n"
998
+ " local unwrap = true\n"
999
+ " local count = 1\n"
1000
+ " if raw_count ~= \"single\" then\n"
1001
+ " count = tonumber(raw_count)\n"
1002
+ " unwrap = false\n"
1254
1003
  " end\n"
1255
- " if inverse then\n"
1256
- " local new_frame = {}\n"
1257
- " for name, new_message in pairs(frame) do\n"
1258
- " new_frame[name] = new_message\n"
1259
- " end\n"
1260
- " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1261
- " for i = 1, #new_mids, 1 do\n"
1262
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1263
- " if not message then\n"
1264
- " cleanup = true\n"
1265
- " elseif not reviewers[index](message, new_frame, index) then\n"
1266
- " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. new_mids[i]\n"
1267
- " redis.call(\"rpush\", frames_key, frame_packers[index - 1](new_frame))\n"
1268
- " result = 0\n"
1269
- " break\n"
1004
+ " if count == 0 then\n"
1005
+ " local packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1006
+ " while packed_frame ~= \"0\" do\n"
1007
+ " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1008
+ " if frame then\n"
1009
+ " table.insert(frames, frame)\n"
1010
+ " table.insert(packed_frames, packed_frame)\n"
1270
1011
  " end\n"
1012
+ " packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1013
+ " end\n"
1014
+ " if #packed_frames > 0 then\n"
1015
+ " redis.call(\"lpush\", rule_action_key, 0)\n"
1271
1016
  " end\n"
1272
1017
  " else\n"
1273
- " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1274
- " for i = 1, #new_mids, 1 do\n"
1275
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1276
- " if not message then\n"
1277
- " cleanup = true\n"
1018
+ " while count > 0 do\n"
1019
+ " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
1020
+ " if not packed_frame then\n"
1021
+ " break\n"
1278
1022
  " else\n"
1279
- " local count = process_event_and_frame(message, frame, index, use_facts)\n"
1280
- " if not result then\n"
1281
- " result = 0\n"
1282
- " end\n"
1283
- " result = result + count\n"
1284
- " if not is_pure_fact(frame, index) then\n"
1285
- " break\n"
1023
+ " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1024
+ " if frame then\n"
1025
+ " table.insert(frames, frame)\n"
1026
+ " table.insert(packed_frames, packed_frame)\n"
1027
+ " count = count - 1\n"
1286
1028
  " end\n"
1287
1029
  " end\n"
1288
1030
  " end\n"
1289
1031
  " end\n"
1290
- " if cleanup then\n"
1291
- " cleanup_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1032
+ " for i = #packed_frames, 1, -1 do\n"
1033
+ " redis.call(\"rpush\", rule_action_key, packed_frames[i])\n"
1292
1034
  " end\n"
1293
- " return result\n"
1294
- "end\n"
1295
- "process_frame = function(frame, index, use_facts)\n"
1296
- " local first_result = process_frame_for_key(frame, index, keys[index] .. \"!e!\" .. sid, false)\n"
1297
- " local second_result = process_frame_for_key(frame, index, keys[index] .. \"!f!\" .. sid, true)\n"
1298
- " if not first_result and not second_result then\n"
1299
- " return process_event_and_frame(nil, frame, index, use_facts)\n"
1300
- " elseif not first_result then\n"
1301
- " return second_result\n"
1302
- " elseif not second_result then\n"
1303
- " return first_result\n"
1035
+ " if #packed_frames == 0 then\n"
1036
+ " return nil, nil\n"
1037
+ " end\n"
1038
+ " local last_name = string.find(rule_action_key, \"!\") - 1\n"
1039
+ " if unwrap then\n"
1040
+ " return string.sub(rule_action_key, 1, last_name), frames[1]\n"
1304
1041
  " else\n"
1305
- " return first_result + second_result\n"
1042
+ " return string.sub(rule_action_key, 1, last_name), frames\n"
1306
1043
  " end\n"
1307
1044
  "end\n"
1308
- "local process_inverse_event = function(message, index, events_key, use_facts)\n"
1309
- " local result = 0\n"
1310
- " local messages_key = events_hashset\n"
1311
- " if use_facts then\n"
1312
- " messages_key = facts_hashset\n"
1045
+ "local load_frame_from_sid = function(sid, max_score)\n"
1046
+ " local action_list = action_key .. \"!\" .. sid\n"
1047
+ " local rule_action_key = redis.call(\"lpop\", action_list)\n"
1048
+ " if not rule_action_key then\n"
1049
+ " return nil, nil\n"
1313
1050
  " end\n"
1314
- " redis.call(\"hdel\", messages_key, mid)\n"
1315
- " if index == 1 then\n"
1316
- " result = process_frame({}, 1, use_facts)\n"
1317
- " else\n"
1318
- " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. mid\n"
1319
- " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
1320
- " for i = 1, packed_frames_len, 1 do\n"
1321
- " local packed_frame = redis.call(\"rpop\", frames_key)\n"
1322
- " local frame = frame_unpackers[index - 1](packed_frame)\n"
1323
- " if frame then\n"
1324
- " result = result + process_frame(frame, index, use_facts)\n"
1325
- " end\n"
1051
+ " local count = redis.call(\"lpop\", action_list)\n"
1052
+ " local name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1053
+ " while not frame do\n"
1054
+ " rule_action_key = redis.call(\"lpop\", action_list)\n"
1055
+ " if not rule_action_key then\n"
1056
+ " return nil, nil\n"
1326
1057
  " end\n"
1058
+ " count = redis.call(\"lpop\", action_list)\n"
1059
+ " name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1327
1060
  " end\n"
1328
- " return result\n"
1061
+ " redis.call(\"lpush\", action_list, count)\n"
1062
+ " redis.call(\"lpush\", action_list, rule_action_key)\n"
1063
+ " return name, frame\n"
1329
1064
  "end\n"
1330
- "local process_event = function(message, index, events_key, use_facts)\n"
1331
- " local result = 0\n"
1332
- " local messages_key = events_hashset\n"
1333
- " if use_facts then\n"
1334
- " messages_key = facts_hashset\n"
1065
+ "local load_frame = function(max_score)\n"
1066
+ " local current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1067
+ " if (#current_action == 0) or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1068
+ " return nil, nil, nil\n"
1335
1069
  " end\n"
1336
- " if index == 1 then\n"
1337
- " result = process_event_and_frame(message, {}, 1, use_facts)\n"
1338
- " else\n"
1339
- " local frames_key\n"
1340
- " local primary_key = primary_message_keys[index](message)\n"
1341
- " if primary_key then\n"
1342
- " frames_key = keys[index] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
1343
- " else\n"
1344
- " frames_key = keys[index] .. \"!c!\" .. sid\n"
1345
- " end\n"
1346
- " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
1347
- " for i = 1, packed_frames_len, 1 do\n"
1348
- " local packed_frame = redis.call(\"rpop\", frames_key)\n"
1349
- " local frame = frame_unpackers[index - 1](packed_frame)\n"
1350
- " if frame then\n"
1351
- " local count = process_event_and_frame(message, frame, index, use_facts)\n"
1352
- " result = result + count\n"
1353
- " if count == 0 or use_facts then\n"
1354
- " redis.call(\"lpush\", frames_key, packed_frame)\n"
1355
- " else\n"
1356
- " break\n"
1357
- " end\n"
1358
- " end\n"
1070
+ " local sid = current_action[1]\n"
1071
+ " local name, frame = load_frame_from_sid(sid, max_score)\n"
1072
+ " while not frame do\n"
1073
+ " redis.call(\"zremrangebyrank\", action_key, 0, 0)\n"
1074
+ " current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1075
+ " if #current_action == 0 or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1076
+ " return nil, nil, nil\n"
1359
1077
  " end\n"
1078
+ " sid = current_action[1]\n"
1079
+ " name, frame = load_frame_from_sid(sid, max_score)\n"
1360
1080
  " end\n"
1361
- " if result == 0 or use_facts then\n"
1362
- " save_message(index, message, events_key, messages_key)\n"
1081
+ " return sid, name, frame\n"
1082
+ "end\n"
1083
+ "get_context = function(action_key)\n"
1084
+ " if context_directory[action_key] then\n"
1085
+ " return context_directory[action_key]\n"
1363
1086
  " end\n"
1364
- " return result\n"
1087
+ " local input_keys = {[action_key] = true}\n%s"
1365
1088
  "end\n"
1366
- "local process_key_with_span = function(message, span)\n"
1367
- " local index = directory[key]\n"
1368
- " local queue_lock = false\n"
1369
- " if index then\n"
1370
- " local last_score = redis.call(\"get\", results_key .. \"!d\")\n"
1371
- " if not last_score then\n"
1372
- " redis.call(\"set\", results_key .. \"!d\", score)\n"
1373
- " else\n"
1374
- " local new_score = last_score + span\n"
1375
- " if score > new_score then\n"
1376
- " redis.call(\"rpush\", results_key, 0)\n"
1377
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1378
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, 0)\n"
1379
- " local span_count, span_remain = math.modf((score - new_score) / span)\n"
1380
- " last_score = new_score + span_count * span\n"
1381
- " redis.call(\"set\", results_key .. \"!d\", last_score)\n"
1382
- " queue_lock = true\n"
1383
- " end\n"
1384
- " end\n"
1385
- " local count = 0\n"
1386
- " if not message then\n"
1387
- " if assert_fact == 0 then\n"
1388
- " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1389
- " else\n"
1390
- " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1391
- " end\n"
1392
- " else\n"
1393
- " if assert_fact == 0 then\n"
1394
- " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1395
- " else\n"
1396
- " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1397
- " end\n"
1398
- " end\n"
1399
- " if (count > 0) then\n"
1400
- " for i = 1, #results, 1 do\n"
1401
- " redis.call(\"rpush\", results_key, results[i])\n"
1402
- " end\n"
1403
- " end\n"
1404
- " end\n"
1405
- " return queue_lock\n"
1089
+ "local new_sid, action_name, frame\n"
1090
+ "if #ARGV == 3 then\n"
1091
+ " new_sid = ARGV[3]\n"
1092
+ " action_name, frame = load_frame_from_sid(new_sid, tonumber(ARGV[2]))\n"
1093
+ "else\n"
1094
+ " new_sid, action_name, frame = load_frame(tonumber(ARGV[2]))\n"
1406
1095
  "end\n"
1407
- "local process_key_with_cap = function(message, cap)\n"
1408
- " local index = directory[key]\n"
1409
- " local queue_lock = false\n"
1410
- " if index then\n"
1411
- " local count = 0\n"
1412
- " if not message then\n"
1413
- " if assert_fact == 0 then\n"
1414
- " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1415
- " else\n"
1416
- " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1417
- " end\n"
1418
- " else\n"
1419
- " if assert_fact == 0 then\n"
1420
- " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1421
- " else\n"
1422
- " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1423
- " end\n"
1424
- " end\n"
1425
- " if (count > 0) then\n"
1426
- " for i = #results, 1, -1 do\n"
1427
- " redis.call(\"lpush\", results_key, results[i])\n"
1428
- " end\n"
1429
- " local diff\n"
1430
- " local new_count, new_remain = math.modf(#results / cap)\n"
1431
- " local new_remain = #results %% cap\n"
1432
- " if new_count > 0 then\n"
1433
- " for i = 1, new_count, 1 do\n"
1434
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1435
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, cap)\n"
1436
- " end\n"
1437
- " end\n"
1438
- " if new_remain > 0 then\n"
1439
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1440
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, new_remain)\n"
1441
- " end\n"
1442
- " if new_count > 0 or new_remain > 0 then\n"
1443
- " queue_lock = true\n"
1444
- " end\n"
1445
- " end\n"
1096
+ "if frame then\n"
1097
+ " redis.call(\"zadd\", action_key, tonumber(ARGV[1]), new_sid)\n"
1098
+ " if #ARGV == 2 then\n"
1099
+ " local state = redis.call(\"hget\", state_key, new_sid)\n"
1100
+ " return {new_sid, state, cjson.encode({[action_name] = frame})}\n"
1101
+ " else\n"
1102
+ " return {new_sid, cjson.encode({[action_name] = frame})}\n"
1446
1103
  " end\n"
1447
- " return queue_lock\n"
1448
- "end\n"
1449
- "local process_key_with_window = function(message, window)\n"
1450
- " local index = directory[key]\n"
1451
- " local queue_lock = false\n"
1452
- " if index then\n"
1453
- " local count = 0\n"
1104
+ "end\n",
1105
+ name,
1106
+ name,
1107
+ name,
1108
+ name,
1109
+ name,
1110
+ peekActionLua) == -1) {
1111
+ return ERR_OUT_OF_MEMORY;
1112
+ }
1113
+ free(peekActionLua);
1114
+ redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
1115
+ redisGetReply(reContext, (void**)&reply);
1116
+ if (reply->type == REDIS_REPLY_ERROR) {
1117
+ printf("%s\n", reply->str);
1118
+ freeReplyObject(reply);
1119
+ free(lua);
1120
+ return ERR_REDIS_ERROR;
1121
+ }
1122
+
1123
+ strncpy(rulesBinding->peekActionHash, reply->str, 40);
1124
+ rulesBinding->peekActionHash[40] = '\0';
1125
+ freeReplyObject(reply);
1126
+ free(lua);
1127
+ return RULES_OK;
1128
+ }
1129
+
1130
+ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding) {
1131
+ char *name = &tree->stringPool[tree->nameOffset];
1132
+ int nameLength = strlen(name);
1133
+ redisContext *reContext = rulesBinding->reContext;
1134
+ redisReply *reply;
1135
+ char *lua = NULL;
1136
+ char *oldLua;
1137
+
1138
+ #ifdef _WIN32
1139
+ char *actionKey = (char *)_alloca(sizeof(char)*(nameLength + 3));
1140
+ sprintf_s(actionKey, nameLength + 3, "%s!a", name);
1141
+ #else
1142
+ char actionKey[nameLength + 3];
1143
+ snprintf(actionKey, nameLength + 3, "%s!a", name);
1144
+ #endif
1145
+
1146
+ lua = (char*)calloc(1, sizeof(char));
1147
+ if (!lua) {
1148
+ return ERR_OUT_OF_MEMORY;
1149
+ }
1150
+
1151
+ for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
1152
+ node *currentNode = &tree->nodePool[i];
1153
+
1154
+ if (currentNode->type == NODE_ACTION) {
1155
+ char *packFrameLua = NULL;
1156
+ char *unpackFrameLua = NULL;
1157
+ char *oldPackFrameLua = NULL;
1158
+ char *oldUnpackFrameLua = NULL;
1159
+ char *actionName = &tree->stringPool[currentNode->nameOffset];
1160
+ char *actionLastName = strchr(actionName, '!');
1161
+ #ifdef _WIN32
1162
+ char *actionAlias = (char *)_alloca(sizeof(char)*(actionLastName - actionName + 1));
1163
+ #else
1164
+ char actionAlias[actionLastName - actionName + 1];
1165
+ #endif
1166
+
1167
+ strncpy(actionAlias, actionName, actionLastName - actionName);
1168
+ actionAlias[actionLastName - actionName] = '\0';
1169
+
1170
+ for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
1171
+ unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
1172
+ join *currentJoin = &tree->joinPool[currentJoinOffset];
1173
+ oldLua = lua;
1174
+ if (asprintf(&lua,
1175
+ "%stoggle = false\n"
1176
+ "context = {}\n"
1177
+ "reviewers = {}\n"
1178
+ "context[\"reviewers\"] = reviewers\n"
1179
+ "frame_packers = {}\n"
1180
+ "context[\"frame_packers\"] = frame_packers\n"
1181
+ "frame_unpackers = {}\n"
1182
+ "context[\"frame_unpackers\"] = frame_unpackers\n"
1183
+ "primary_message_keys = {}\n"
1184
+ "context[\"primary_message_keys\"] = primary_message_keys\n"
1185
+ "primary_frame_keys = {}\n"
1186
+ "context[\"primary_frame_keys\"] = primary_frame_keys\n"
1187
+ "keys = {}\n"
1188
+ "context[\"keys\"] = keys\n"
1189
+ "inverse_directory = {}\n"
1190
+ "context[\"inverse_directory\"] = inverse_directory\n"
1191
+ "directory = {[\"0\"] = 1}\n"
1192
+ "context[\"directory\"] = directory\n"
1193
+ "context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
1194
+ "context[\"expressions_count\"] = %d\n",
1195
+ lua,
1196
+ actionName,
1197
+ ii,
1198
+ currentJoin->expressionsLength) == -1) {
1199
+ return ERR_OUT_OF_MEMORY;
1200
+ }
1201
+ free(oldLua);
1202
+
1203
+ for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
1204
+ unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
1205
+ expression *expr = &tree->expressionPool[expressionOffset];
1206
+ char *currentAlias = &tree->stringPool[expr->aliasOffset];
1207
+ char *currentKey = &tree->stringPool[expr->nameOffset];
1208
+ char *nextKeyTest;
1209
+ if (iii == (currentJoin->expressionsLength - 1)) {
1210
+ nextKeyTest = (char*)calloc(1, sizeof(char));
1211
+ if (!nextKeyTest) {
1212
+ return ERR_OUT_OF_MEMORY;
1213
+ }
1214
+ } else {
1215
+ unsigned int nextExpressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii + 1];
1216
+ expression *nextExpr = &tree->expressionPool[nextExpressionOffset];
1217
+ if (asprintf(&nextKeyTest,
1218
+ "or input_keys[\"%s\"]",
1219
+ &tree->stringPool[nextExpr->nameOffset]) == -1) {
1220
+ return ERR_OUT_OF_MEMORY;
1221
+ }
1222
+ }
1223
+
1224
+ if (iii == 0) {
1225
+ if (expr->not) {
1226
+ if (asprintf(&packFrameLua,
1227
+ " result[1] = \"$n\"\n") == -1) {
1228
+ return ERR_OUT_OF_MEMORY;
1229
+ }
1230
+
1231
+ if (asprintf(&unpackFrameLua,
1232
+ " result[\"%s\"] = \"$n\"\n",
1233
+ currentAlias) == -1) {
1234
+ return ERR_OUT_OF_MEMORY;
1235
+ }
1236
+
1237
+ oldLua = lua;
1238
+ if (asprintf(&lua,
1239
+ "%sif input_keys[\"%s\"] %s then\n"
1240
+ " toggle = true\n"
1241
+ " context_directory[\"%s\"] = context\n"
1242
+ " keys[1] = \"%s\"\n"
1243
+ " inverse_directory[1] = true\n"
1244
+ " directory[\"%s\"] = 1\n"
1245
+ " reviewers[1] = function(message, frame, index)\n"
1454
1246
  " if not message then\n"
1455
- " if assert_fact == 0 then\n"
1456
- " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1457
- " else\n"
1458
- " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1459
- " end\n"
1460
- " else\n"
1461
- " if assert_fact == 0 then\n"
1462
- " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1463
- " else\n"
1464
- " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1465
- " end\n"
1247
+ " frame[\"%s\"] = \"$n\"\n"
1248
+ " return true\n"
1466
1249
  " end\n"
1467
- " if (count > 0) then\n"
1468
- " for i = #results, 1, -1 do\n"
1469
- " redis.call(\"lpush\", results_key, results[i])\n"
1470
- " end\n"
1471
- " local diff\n"
1472
- " local length = redis.call(\"llen\", results_key)\n"
1473
- " local prev_count, prev_remain = math.modf((length - count) / window)\n"
1474
- " local new_count, prev_remain = math.modf(length / window)\n"
1475
- " diff = new_count - prev_count\n"
1476
- " if diff > 0 then\n"
1477
- " for i = 0, diff - 1, 1 do\n"
1478
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1479
- " if window == 1 then\n"
1480
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"single\")\n"
1481
- " else\n"
1482
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, window)\n"
1483
- " end\n"
1484
- " end\n"
1485
- " queue_lock = true\n"
1486
- " end\n"
1250
+ " return false\n"
1251
+ " end\n"
1252
+ " frame_packers[1] = function(frame, full_encode)\n"
1253
+ " local result = {}\n%s"
1254
+ " return cmsgpack.pack(result)\n"
1255
+ " end\n"
1256
+ " frame_unpackers[1] = function(packed_frame)\n"
1257
+ " local frame = cmsgpack.unpack(packed_frame)\n"
1258
+ " local result = {}\n%s"
1259
+ " return result\n"
1260
+ " end\n"
1261
+ " primary_message_keys[1] = function(message)\n"
1262
+ " return \"\"\n"
1263
+ " end\n"
1264
+ " primary_frame_keys[1] = function(frame)\n"
1265
+ " return \"\"\n"
1266
+ " end\n"
1267
+ "end\n",
1268
+ lua,
1269
+ currentKey,
1270
+ nextKeyTest,
1271
+ currentKey,
1272
+ currentKey,
1273
+ currentKey,
1274
+ currentAlias,
1275
+ packFrameLua,
1276
+ unpackFrameLua) == -1) {
1277
+ return ERR_OUT_OF_MEMORY;
1278
+ }
1279
+ free(oldLua);
1280
+ // not (expr->not)
1281
+ } else {
1282
+ if (asprintf(&packFrameLua,
1283
+ " message = frame[\"%s\"]\n"
1284
+ " if full_encode and not message[\"$f\"] then\n"
1285
+ " result[1] = message\n"
1286
+ " else\n"
1287
+ " result[1] = message[\"id\"]\n"
1288
+ " end\n",
1289
+ currentAlias) == -1) {
1290
+ return ERR_OUT_OF_MEMORY;
1291
+ }
1292
+
1293
+ if (asprintf(&unpackFrameLua,
1294
+ " message = fetch_message(frame[1])\n"
1295
+ " if not message then\n"
1296
+ " return nil\n"
1297
+ " end\n"
1298
+ " result[\"%s\"] = message\n",
1299
+ currentAlias) == -1) {
1300
+ return ERR_OUT_OF_MEMORY;
1301
+ }
1302
+
1303
+ oldLua = lua;
1304
+ if (asprintf(&lua,
1305
+ "%sif input_keys[\"%s\"] %s then\n"
1306
+ " toggle = true\n"
1307
+ " context_directory[\"%s\"] = context\n"
1308
+ " keys[1] = \"%s\"\n"
1309
+ " inverse_directory[1] = true\n"
1310
+ " directory[\"%s\"] = 1\n"
1311
+ " reviewers[1] = function(message, frame, index)\n"
1312
+ " if message then\n"
1313
+ " frame[\"%s\"] = message\n"
1314
+ " return true\n"
1487
1315
  " end\n"
1316
+ " return false\n"
1488
1317
  " end\n"
1489
- " return queue_lock\n"
1490
- "end\n"
1491
- "local message = nil\n"
1492
- "if #ARGV > (6 + keys_count) then\n"
1493
- " message = {}\n"
1494
- " for index = 6 + keys_count, #ARGV, 3 do\n"
1495
- " if ARGV[index + 2] == \"1\" then\n"
1496
- " message[ARGV[index]] = ARGV[index + 1]\n"
1497
- " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
1498
- " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
1499
- " elseif ARGV[index + 2] == \"4\" then\n"
1500
- " if ARGV[index + 1] == \"true\" then\n"
1501
- " message[ARGV[index]] = true\n"
1502
- " else\n"
1503
- " message[ARGV[index]] = false\n"
1504
- " end\n"
1505
- " end\n"
1318
+ " frame_packers[1] = function(frame, full_encode)\n"
1319
+ " local result = {}\n"
1320
+ " local message\n%s"
1321
+ " return cmsgpack.pack(result)\n"
1506
1322
  " end\n"
1507
- " if assert_fact == 1 then\n"
1508
- " message[\"$f\"] = 1\n"
1323
+ " frame_unpackers[1] = function(packed_frame)\n"
1324
+ " local frame = cmsgpack.unpack(packed_frame)\n"
1325
+ " local result = {}\n"
1326
+ " local message\n%s"
1327
+ " return result\n"
1509
1328
  " end\n"
1510
- "end\n"
1511
- "if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
1512
- " if assert_fact == 0 then\n"
1513
- " if message and redis.call(\"hexists\", events_hashset, mid) == 0 then\n"
1514
- " return false\n"
1329
+ " primary_message_keys[1] = function(message)\n"
1330
+ " return \"\"\n"
1331
+ " end\n"
1332
+ " primary_frame_keys[1] = function(frame)\n"
1333
+ " return \"\"\n"
1334
+ " end\n"
1335
+ "end\n",
1336
+ lua,
1337
+ currentKey,
1338
+ nextKeyTest,
1339
+ currentKey,
1340
+ currentKey,
1341
+ currentKey,
1342
+ currentAlias,
1343
+ packFrameLua,
1344
+ unpackFrameLua) == -1) {
1345
+ return ERR_OUT_OF_MEMORY;
1346
+ }
1347
+ free(oldLua);
1348
+ }
1349
+ // not (iii == 0)
1350
+ } else {
1351
+ char *test = NULL;
1352
+ char *primaryKeyLua = NULL;
1353
+ char *primaryFrameKeyLua = NULL;
1354
+ unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
1355
+ if (result != RULES_OK) {
1356
+ return result;
1357
+ }
1358
+
1359
+ if (expr->not) {
1360
+ oldPackFrameLua = packFrameLua;
1361
+ if (asprintf(&packFrameLua,
1362
+ "%s result[%d] = \"$n\"\n",
1363
+ packFrameLua,
1364
+ iii + 1) == -1) {
1365
+ return ERR_OUT_OF_MEMORY;
1366
+ }
1367
+ free(oldPackFrameLua);
1368
+
1369
+ oldUnpackFrameLua = unpackFrameLua;
1370
+ if (asprintf(&unpackFrameLua,
1371
+ "%s result[\"%s\"] = \"$n\"\n",
1372
+ unpackFrameLua,
1373
+ currentAlias) == -1) {
1374
+ return ERR_OUT_OF_MEMORY;
1375
+ }
1376
+ free(oldUnpackFrameLua);
1377
+
1378
+ oldLua = lua;
1379
+ if (asprintf(&lua,
1380
+ "%sif toggle %s then\n"
1381
+ " toggle = true\n"
1382
+ " context_directory[\"%s\"] = context\n"
1383
+ " keys[%d] = \"%s\"\n"
1384
+ " inverse_directory[%d] = true\n"
1385
+ " directory[\"%s\"] = %d\n"
1386
+ " reviewers[%d] = function(message, frame, index)\n"
1387
+ " if not message or not (%s) then\n"
1388
+ " frame[\"%s\"] = \"$n\"\n"
1389
+ " return true\n"
1515
1390
  " end\n"
1391
+ " return false\n"
1392
+ " end\n"
1393
+ " frame_packers[%d] = function(frame, full_encode)\n"
1394
+ " local result = {}\n"
1395
+ " local message\n%s"
1396
+ " return cmsgpack.pack(result)\n"
1397
+ " end\n"
1398
+ " frame_unpackers[%d] = function(packed_frame)\n"
1399
+ " local frame = cmsgpack.unpack(packed_frame)\n"
1400
+ " local result = {}\n"
1401
+ " local message\n%s"
1402
+ " return result\n"
1403
+ " end\n"
1404
+ " primary_message_keys[%d] = function(message)\n"
1405
+ " local result = \"\"\n%s"
1406
+ " return result\n"
1407
+ " end\n"
1408
+ " primary_frame_keys[%d] = function(frame)\n"
1409
+ " local result = \"\"\n%s"
1410
+ " return result\n"
1411
+ " end\n"
1412
+ "end\n",
1413
+ lua,
1414
+ nextKeyTest,
1415
+ currentKey,
1416
+ iii + 1,
1417
+ currentKey,
1418
+ iii + 1,
1419
+ currentKey,
1420
+ iii + 1,
1421
+ iii + 1,
1422
+ test,
1423
+ currentAlias,
1424
+ iii + 1,
1425
+ packFrameLua,
1426
+ iii + 1,
1427
+ unpackFrameLua,
1428
+ iii + 1,
1429
+ primaryKeyLua,
1430
+ iii + 1,
1431
+ primaryFrameKeyLua) == -1) {
1432
+ return ERR_OUT_OF_MEMORY;
1433
+ }
1434
+ free(oldLua);
1435
+
1436
+ // not (expr->not)
1437
+ } else {
1438
+ oldPackFrameLua = packFrameLua;
1439
+ if (asprintf(&packFrameLua,
1440
+ "%s message = frame[\"%s\"]\n"
1441
+ " if full_encode and not message[\"$f\"] then\n"
1442
+ " result[%d] = message\n"
1516
1443
  " else\n"
1517
- " if message and redis.call(\"hexists\", facts_hashset, mid) == 0 then\n"
1518
- " return false\n"
1444
+ " result[%d] = message[\"id\"]\n"
1445
+ " end\n",
1446
+ packFrameLua,
1447
+ currentAlias,
1448
+ iii + 1,
1449
+ iii + 1) == -1) {
1450
+ return ERR_OUT_OF_MEMORY;
1451
+ }
1452
+ free(oldPackFrameLua);
1453
+
1454
+ oldUnpackFrameLua = unpackFrameLua;
1455
+ if (asprintf(&unpackFrameLua,
1456
+ "%s message = fetch_message(frame[%d])\n"
1457
+ " if not message then\n"
1458
+ " return nil\n"
1459
+ " end\n"
1460
+ " result[\"%s\"] = message\n",
1461
+ unpackFrameLua,
1462
+ iii + 1,
1463
+ currentAlias) == -1) {
1464
+ return ERR_OUT_OF_MEMORY;
1465
+ }
1466
+ free(oldUnpackFrameLua);
1467
+
1468
+ oldLua = lua;
1469
+ if (asprintf(&lua,
1470
+ "%sif toggle %s then\n"
1471
+ " toggle = true\n"
1472
+ " context_directory[\"%s\"] = context\n"
1473
+ " keys[%d] = \"%s\"\n"
1474
+ " directory[\"%s\"] = %d\n"
1475
+ " reviewers[%d] = function(message, frame, index)\n"
1476
+ " if message and %s then\n"
1477
+ " frame[\"%s\"] = message\n"
1478
+ " return true\n"
1519
1479
  " end\n"
1480
+ " return false\n"
1520
1481
  " end\n"
1521
- "end\n"
1522
- "for index = 6, 5 + keys_count, 1 do\n"
1523
- " input_keys[ARGV[index]] = true\n"
1524
- "end\n"
1525
- "%sfor index = 6, 5 + keys_count, 1 do\n"
1526
- " results = {}\n"
1527
- " unpacked_results = {}\n"
1528
- " key = ARGV[index]\n"
1529
- " context = context_directory[key]\n"
1530
- " keys = context[\"keys\"]\n"
1531
- " reviewers = context[\"reviewers\"]\n"
1532
- " frame_packers = context[\"frame_packers\"]\n"
1533
- " frame_unpackers = context[\"frame_unpackers\"]\n"
1534
- " primary_message_keys = context[\"primary_message_keys\"]\n"
1535
- " primary_frame_keys = context[\"primary_frame_keys\"]\n"
1536
- " directory = context[\"directory\"]\n"
1537
- " results_key = context[\"results_key\"]\n"
1538
- " inverse_directory = context[\"inverse_directory\"]\n"
1539
- " expressions_count = context[\"expressions_count\"]\n"
1540
- " local process_key = context[\"process_key\"]\n"
1541
- " local process_key_count = context[\"process_key_count\"]\n"
1542
- " queue_action = process_key(message, process_key_count)\n"
1543
- " if assert_fact == 0 and events_message_cache[tostring(message[\"id\"])] == false then\n"
1544
- " break\n"
1482
+ " frame_packers[%d] = function(frame, full_encode)\n"
1483
+ " local result = {}\n"
1484
+ " local message\n%s"
1485
+ " return cmsgpack.pack(result)\n"
1545
1486
  " end\n"
1546
- "end\n"
1547
- "if queue_action then\n"
1548
- " if not redis.call(\"zscore\", actions_key, sid) then\n"
1549
- " redis.call(\"zadd\", actions_key , score, sid)\n"
1487
+ " frame_unpackers[%d] = function(packed_frame)\n"
1488
+ " local frame = cmsgpack.unpack(packed_frame)\n"
1489
+ " local result = {}\n"
1490
+ " local message\n%s"
1491
+ " return result\n"
1550
1492
  " end\n"
1551
- "end\n"
1552
- "return nil\n",
1553
- name,
1554
- name,
1555
- name,
1556
- name,
1557
- name,
1558
- lua) == -1) {
1559
- return ERR_OUT_OF_MEMORY;
1560
- }
1493
+ " primary_message_keys[%d] = function(message)\n"
1494
+ " local result = \"\"\n%s"
1495
+ " return result\n"
1496
+ " end\n"
1497
+ " primary_frame_keys[%d] = function(frame)\n"
1498
+ " local result = \"\"\n%s"
1499
+ " return result\n"
1500
+ " end\n"
1501
+ "end\n",
1502
+ lua,
1503
+ nextKeyTest,
1504
+ currentKey,
1505
+ iii + 1,
1506
+ currentKey,
1507
+ currentKey,
1508
+ iii + 1,
1509
+ iii + 1,
1510
+ test,
1511
+ currentAlias,
1512
+ iii + 1,
1513
+ packFrameLua,
1514
+ iii + 1,
1515
+ unpackFrameLua,
1516
+ iii + 1,
1517
+ primaryKeyLua,
1518
+ iii + 1,
1519
+ primaryFrameKeyLua) == -1) {
1520
+ return ERR_OUT_OF_MEMORY;
1521
+ }
1522
+ free(oldLua);
1523
+ // done not (expr->not)
1524
+ }
1525
+ free(nextKeyTest);
1526
+ free(test);
1527
+ free(primaryKeyLua);
1528
+ free(primaryFrameKeyLua);
1529
+ // done not (iii == 0)
1530
+ }
1531
+ }
1561
1532
 
1562
- free(oldLua);
1563
- redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
1564
- redisGetReply(reContext, (void**)&reply);
1565
- if (reply->type == REDIS_REPLY_ERROR) {
1566
- printf("%s\n", reply->str);
1567
- freeReplyObject(reply);
1568
- free(lua);
1569
- return ERR_REDIS_ERROR;
1570
- }
1533
+ if (currentNode->value.c.span > 0) {
1534
+ oldLua = lua;
1535
+ if (asprintf(&lua,
1536
+ "%sif toggle then\n"
1537
+ " context[\"process_key\"] = process_key_with_span\n"
1538
+ " context[\"process_key_count\"] = %d\n"
1539
+ "end\n",
1540
+ lua,
1541
+ currentNode->value.c.span) == -1) {
1542
+ return ERR_OUT_OF_MEMORY;
1543
+ }
1544
+ free(oldLua);
1571
1545
 
1572
- strncpy(rulesBinding->evalMessageHash, reply->str, 40);
1573
- rulesBinding->evalMessageHash[40] = '\0';
1574
- freeReplyObject(reply);
1575
- free(lua);
1546
+ } else if (currentNode->value.c.cap > 0) {
1547
+ oldLua = lua;
1548
+ if (asprintf(&lua,
1549
+ "%sif toggle then\n"
1550
+ " context[\"process_key\"] = process_key_with_cap\n"
1551
+ " context[\"process_key_count\"] = %d\n"
1552
+ "end\n",
1553
+ lua,
1554
+ currentNode->value.c.cap) == -1) {
1555
+ return ERR_OUT_OF_MEMORY;
1556
+ }
1557
+ free(oldLua);
1576
1558
 
1577
- if (asprintf(&lua,
1578
- "local facts_key = \"%s!f!\"\n"
1579
- "local events_key = \"%s!e!\"\n"
1580
- "local action_key = \"%s!a\"\n"
1559
+ } else {
1560
+ oldLua = lua;
1561
+ if (asprintf(&lua,
1562
+ "%sif toggle then\n"
1563
+ " context[\"process_key\"] = process_key_with_window\n"
1564
+ " context[\"process_key_count\"] = %d\n"
1565
+ "end\n",
1566
+ lua,
1567
+ currentNode->value.c.count) == -1) {
1568
+ return ERR_OUT_OF_MEMORY;
1569
+ }
1570
+ free(oldLua);
1571
+ }
1572
+ }
1573
+
1574
+ free(unpackFrameLua);
1575
+ free(packFrameLua);
1576
+ }
1577
+ }
1578
+
1579
+ oldLua = lua;
1580
+ if (asprintf(&lua,
1581
+ "local sid = ARGV[1]\n"
1582
+ "local mid = ARGV[2]\n"
1583
+ "local score = tonumber(ARGV[3])\n"
1584
+ "local assert_fact = tonumber(ARGV[4])\n"
1585
+ "local keys_count = tonumber(ARGV[5])\n"
1586
+ "local events_hashset = \"%s!e!\" .. sid\n"
1587
+ "local facts_hashset = \"%s!f!\" .. sid\n"
1588
+ "local visited_hashset = \"%s!v!\" .. sid\n"
1589
+ "local actions_key = \"%s!a\"\n"
1581
1590
  "local state_key = \"%s!s\"\n"
1582
- "local timers_key = \"%s!t\"\n"
1591
+ "local queue_action = false\n"
1592
+ "local facts_message_cache = {}\n"
1593
+ "local events_message_cache = {}\n"
1594
+ "local facts_mids_cache = {}\n"
1595
+ "local events_mids_cache = {}\n"
1583
1596
  "local context_directory = {}\n"
1597
+ "local input_keys = {}\n"
1598
+ "local toggle\n"
1599
+ "local expressions_count\n"
1600
+ "local results\n"
1601
+ "local unpacked_results\n"
1602
+ "local context\n"
1584
1603
  "local keys\n"
1585
1604
  "local reviewers\n"
1605
+ "local frame_packers\n"
1606
+ "local frame_unpackers\n"
1607
+ "local primary_message_keys\n"
1586
1608
  "local primary_frame_keys\n"
1587
- "local facts_hashset\n"
1588
- "local events_hashset\n"
1589
- "local events_message_cache = {}\n"
1590
- "local facts_message_cache = {}\n"
1591
- "local facts_mids_cache = {}\n"
1592
- "local events_mids_cache = {}\n"
1593
- "local get_context\n"
1609
+ "local directory\n"
1610
+ "local results_key\n"
1611
+ "local inverse_directory\n"
1612
+ "local key\n"
1613
+ "local cleanup_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1614
+ " local event_mids = mids_cache[events_key]\n"
1615
+ " local primary_key = primary_frame_keys[index](frame)\n"
1616
+ " local new_mids = event_mids[primary_key]\n"
1617
+ " local result_mids = {}\n"
1618
+ " for i = 1, #new_mids, 1 do\n"
1619
+ " local new_mid = new_mids[i]\n"
1620
+ " if message_cache[new_mid] ~= false then\n"
1621
+ " table.insert(result_mids, new_mid)\n"
1622
+ " end\n"
1623
+ " end\n"
1624
+ " event_mids[primary_key] = result_mids\n"
1625
+ " redis.call(\"del\", events_key .. \"!m!\" .. primary_key)\n"
1626
+ " for i = 1, #result_mids, 1 do\n"
1627
+ " redis.call(\"rpush\", events_key .. \"!m!\" .. primary_key, result_mids[i])\n"
1628
+ " end\n"
1629
+ "end\n"
1594
1630
  "local get_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1595
1631
  " local event_mids = mids_cache[events_key]\n"
1596
1632
  " local primary_key = primary_frame_keys[index](frame)\n"
@@ -1622,258 +1658,381 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
1622
1658
  " return message\n"
1623
1659
  "end\n"
1624
1660
  "local fetch_message = function(new_mid)\n"
1625
- " if type(new_mid) == \"table\" then\n"
1626
- " return new_mid\n"
1661
+ " local message = get_message(new_mid, events_hashset, events_message_cache)\n"
1662
+ " if not message then\n"
1663
+ " message = get_message(new_mid, facts_hashset, facts_message_cache)\n"
1627
1664
  " end\n"
1628
- " return get_message(new_mid, facts_hashset, facts_message_cache)\n"
1665
+ " return message\n"
1629
1666
  "end\n"
1630
- "local validate_frame_for_key = function(packed_frame, frame, index, events_list_key, messages_key, mids_cache, message_cache, sid)\n"
1631
- " local new_mids = get_mids(index, frame, events_list_key, messages_key, mids_cache, message_cache)\n"
1632
- " for i = 1, #new_mids, 1 do\n"
1633
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1634
- " if message and not reviewers[index](message, frame, index) then\n"
1635
- " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. new_mids[i]\n"
1636
- " redis.call(\"rpush\", frames_key, packed_frame)\n"
1637
- " return false\n"
1667
+ "local save_message = function(index, message, events_key, messages_key)\n"
1668
+ " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
1669
+ " local primary_key = primary_message_keys[index](message)\n"
1670
+ " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
1671
+ "end\n"
1672
+ "local save_result = function(frame, index)\n"
1673
+ " table.insert(results, 1, frame_packers[index](frame, true))\n"
1674
+ " table.insert(unpacked_results, 1, frame)\n"
1675
+ " for name, message in pairs(frame) do\n"
1676
+ " if message ~= \"$n\" and not message[\"$f\"] then\n"
1677
+ " redis.call(\"hdel\", events_hashset, message[\"id\"])\n"
1678
+ // message cache always looked up using strings
1679
+ " events_message_cache[tostring(message[\"id\"])] = false\n"
1638
1680
  " end\n"
1639
1681
  " end\n"
1640
- " return true\n"
1641
1682
  "end\n"
1642
- "local validate_frame = function(packed_frame, frame, index, sid)\n"
1643
- " local first_result = validate_frame_for_key(packed_frame, frame, index, keys[index] .. \"!e!\" .. sid, events_hashset, events_mids_cache, events_message_cache, sid)\n"
1644
- " local second_result = validate_frame_for_key(packed_frame, frame, index, keys[index] ..\"!f!\" .. sid, facts_hashset, facts_mids_cache, facts_message_cache, sid)\n"
1645
- " return first_result and second_result\n"
1646
- "end\n"
1647
- "local review_frame = function(frame, rule_action_key, sid, max_score)\n"
1648
- " local indexes = {}\n"
1649
- " local action_id = string.sub(rule_action_key, 1, (string.len(sid) + 1) * -1)\n"
1650
- " local context = get_context(action_id)\n"
1651
- " local full_frame = {}\n"
1652
- " local cancel = false\n"
1653
- " events_hashset = events_key .. sid\n"
1654
- " facts_hashset = facts_key .. sid\n"
1655
- " keys = context[\"keys\"]\n"
1656
- " reviewers = context[\"reviewers\"]\n"
1657
- " primary_frame_keys = context[\"primary_frame_keys\"]\n"
1658
- " if not context[\"frame_restore\"](frame, full_frame) then\n"
1659
- " cancel = true\n"
1660
- " else\n"
1661
- " for i = 1, #frame, 1 do\n"
1662
- " if frame[i] == \"$n\" then\n"
1663
- " if not validate_frame(frame, full_frame, i, sid) then\n"
1664
- " cancel = true\n"
1665
- " break\n"
1666
- " end\n"
1667
- " end\n"
1683
+ "local is_pure_fact = function(frame, index)\n"
1684
+ " local message_count = 0\n"
1685
+ " for name, message in pairs(frame) do\n"
1686
+ " if message ~= 1 and message[\"$f\"] ~= 1 then\n"
1687
+ " return false\n"
1668
1688
  " end\n"
1689
+ " message_count = message_count + 1\n"
1690
+ " end\n"
1691
+ " return (message_count == index - 1)\n"
1692
+ "end\n"
1693
+ "local process_frame\n"
1694
+ "local process_event_and_frame = function(message, frame, index, use_facts)\n"
1695
+ " local result = 0\n"
1696
+ " local new_frame = {}\n"
1697
+ " for name, new_message in pairs(frame) do\n"
1698
+ " new_frame[name] = new_message\n"
1669
1699
  " end\n"
1670
- " if cancel then\n"
1671
- " for i = 1, #frame, 1 do\n"
1672
- " if type(frame[i]) == \"table\" then\n"
1673
- " redis.call(\"hsetnx\", events_hashset, frame[i][\"id\"], cmsgpack.pack(frame[i]))\n"
1674
- " redis.call(\"zadd\", timers_key, max_score, \"p:\" .. cjson.encode(frame[i]))\n"
1700
+ " if reviewers[index](message, new_frame, index) then\n"
1701
+ " if (index == expressions_count) then\n"
1702
+ " save_result(new_frame, index)\n"
1703
+ " return 1\n"
1704
+ " else\n"
1705
+ " result = process_frame(new_frame, index + 1, use_facts)\n"
1706
+ " if result == 0 or use_facts then\n"
1707
+ " local frames_key\n"
1708
+ " local primary_key = primary_frame_keys[index + 1](new_frame)\n"
1709
+ " frames_key = keys[index + 1] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
1710
+ " redis.call(\"rpush\", frames_key, frame_packers[index](new_frame))\n"
1675
1711
  " end\n"
1676
1712
  " end\n"
1677
- " full_frame = nil\n"
1678
1713
  " end\n"
1679
- " return full_frame\n"
1714
+ " return result\n"
1680
1715
  "end\n"
1681
- "local load_frame_from_rule = function(rule_action_key, raw_count, sid, max_score)\n"
1682
- " local frames = {}\n"
1683
- " local packed_frames = {}\n"
1684
- " local unwrap = true\n"
1685
- " local count = 1\n"
1686
- " if raw_count ~= \"single\" then\n"
1687
- " count = tonumber(raw_count)\n"
1688
- " unwrap = false\n"
1716
+ "local process_frame_for_key = function(frame, index, events_key, use_facts)\n"
1717
+ " local result = nil\n"
1718
+ " local inverse = inverse_directory[index]\n"
1719
+ " local messages_key = events_hashset\n"
1720
+ " local message_cache = events_message_cache\n"
1721
+ " local mids_cache = events_mids_cache\n"
1722
+ " local cleanup = false\n"
1723
+ " if use_facts then\n"
1724
+ " messages_key = facts_hashset\n"
1725
+ " message_cache = facts_message_cache\n"
1726
+ " mids_cache = facts_mids_cache\n"
1689
1727
  " end\n"
1690
- " if count == 0 then\n"
1691
- " local packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1692
- " while packed_frame ~= \"0\" do\n"
1693
- " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1694
- " if frame then\n"
1695
- " table.insert(frames, frame)\n"
1696
- " table.insert(packed_frames, packed_frame)\n"
1728
+ " if inverse then\n"
1729
+ " local new_frame = {}\n"
1730
+ " for name, new_message in pairs(frame) do\n"
1731
+ " new_frame[name] = new_message\n"
1732
+ " end\n"
1733
+ " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1734
+ " for i = 1, #new_mids, 1 do\n"
1735
+ " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1736
+ " if not message then\n"
1737
+ " cleanup = true\n"
1738
+ " elseif not reviewers[index](message, new_frame, index) then\n"
1739
+ " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. new_mids[i]\n"
1740
+ " redis.call(\"rpush\", frames_key, frame_packers[index - 1](new_frame))\n"
1741
+ " result = 0\n"
1742
+ " break\n"
1697
1743
  " end\n"
1698
- " packed_frame = redis.call(\"lpop\", rule_action_key)\n"
1699
- " end\n"
1700
- " if #packed_frames > 0 then\n"
1701
- " redis.call(\"lpush\", rule_action_key, 0)\n"
1702
1744
  " end\n"
1703
1745
  " else\n"
1704
- " while count > 0 do\n"
1705
- " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
1706
- " if not packed_frame then\n"
1707
- " break\n"
1746
+ " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1747
+ " for i = 1, #new_mids, 1 do\n"
1748
+ " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1749
+ " if not message then\n"
1750
+ " cleanup = true\n"
1708
1751
  " else\n"
1709
- " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1710
- " if frame then\n"
1711
- " table.insert(frames, frame)\n"
1712
- " table.insert(packed_frames, packed_frame)\n"
1713
- " count = count - 1\n"
1752
+ " local count = process_event_and_frame(message, frame, index, use_facts)\n"
1753
+ " if not result then\n"
1754
+ " result = 0\n"
1755
+ " end\n"
1756
+ " result = result + count\n"
1757
+ " if not is_pure_fact(frame, index) then\n"
1758
+ " break\n"
1714
1759
  " end\n"
1715
1760
  " end\n"
1716
1761
  " end\n"
1717
1762
  " end\n"
1718
- " for i = #packed_frames, 1, -1 do\n"
1719
- " redis.call(\"rpush\", rule_action_key, packed_frames[i])\n"
1720
- " end\n"
1721
- " if #packed_frames == 0 then\n"
1722
- " return nil, nil\n"
1763
+ " if cleanup then\n"
1764
+ " cleanup_mids(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1723
1765
  " end\n"
1724
- " local last_name = string.find(rule_action_key, \"!\") - 1\n"
1725
- " if unwrap then\n"
1726
- " return string.sub(rule_action_key, 1, last_name), frames[1]\n"
1766
+ " return result\n"
1767
+ "end\n"
1768
+ "process_frame = function(frame, index, use_facts)\n"
1769
+ " local first_result = process_frame_for_key(frame, index, keys[index] .. \"!e!\" .. sid, false)\n"
1770
+ " local second_result = process_frame_for_key(frame, index, keys[index] .. \"!f!\" .. sid, true)\n"
1771
+ " if not first_result and not second_result then\n"
1772
+ " return process_event_and_frame(nil, frame, index, use_facts)\n"
1773
+ " elseif not first_result then\n"
1774
+ " return second_result\n"
1775
+ " elseif not second_result then\n"
1776
+ " return first_result\n"
1727
1777
  " else\n"
1728
- " return string.sub(rule_action_key, 1, last_name), frames\n"
1778
+ " return first_result + second_result\n"
1729
1779
  " end\n"
1730
1780
  "end\n"
1731
- "local load_frame_from_sid = function(sid, max_score)\n"
1732
- " local action_list = action_key .. \"!\" .. sid\n"
1733
- " local rule_action_key = redis.call(\"lpop\", action_list)\n"
1734
- " if not rule_action_key then\n"
1735
- " return nil, nil\n"
1781
+ "local process_inverse_event = function(message, index, events_key, use_facts)\n"
1782
+ " local result = 0\n"
1783
+ " local messages_key = events_hashset\n"
1784
+ " if use_facts then\n"
1785
+ " messages_key = facts_hashset\n"
1736
1786
  " end\n"
1737
- " local count = redis.call(\"lpop\", action_list)\n"
1738
- " local name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1739
- " while not frame do\n"
1740
- " rule_action_key = redis.call(\"lpop\", action_list)\n"
1741
- " if not rule_action_key then\n"
1742
- " return nil, nil\n"
1787
+ " redis.call(\"hdel\", messages_key, mid)\n"
1788
+ " if index == 1 then\n"
1789
+ " result = process_frame({}, 1, use_facts)\n"
1790
+ " else\n"
1791
+ " local frames_key = keys[index] .. \"!i!\" .. sid .. \"!\" .. mid\n"
1792
+ " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
1793
+ " for i = 1, packed_frames_len, 1 do\n"
1794
+ " local packed_frame = redis.call(\"rpop\", frames_key)\n"
1795
+ " local frame = frame_unpackers[index - 1](packed_frame)\n"
1796
+ " if frame then\n"
1797
+ " result = result + process_frame(frame, index, use_facts)\n"
1798
+ " end\n"
1743
1799
  " end\n"
1744
- " count = redis.call(\"lpop\", action_list)\n"
1745
- " name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1746
1800
  " end\n"
1747
- " redis.call(\"lpush\", action_list, count)\n"
1748
- " redis.call(\"lpush\", action_list, rule_action_key)\n"
1749
- " return name, frame\n"
1801
+ " return result\n"
1750
1802
  "end\n"
1751
- "local load_frame = function(max_score)\n"
1752
- " local current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1753
- " if (#current_action == 0) or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1754
- " return nil, nil, nil\n"
1803
+ "local process_event = function(message, index, events_key, use_facts)\n"
1804
+ " local result = 0\n"
1805
+ " local messages_key = events_hashset\n"
1806
+ " if use_facts then\n"
1807
+ " messages_key = facts_hashset\n"
1755
1808
  " end\n"
1756
- " local sid = current_action[1]\n"
1757
- " local name, frame = load_frame_from_sid(sid, max_score)\n"
1758
- " while not frame do\n"
1759
- " redis.call(\"zremrangebyrank\", action_key, 0, 0)\n"
1760
- " current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1761
- " if #current_action == 0 or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1762
- " return nil, nil, nil\n"
1809
+ " if index == 1 then\n"
1810
+ " result = process_event_and_frame(message, {}, 1, use_facts)\n"
1811
+ " else\n"
1812
+ " local frames_key\n"
1813
+ " local primary_key = primary_message_keys[index](message)\n"
1814
+ " if primary_key then\n"
1815
+ " frames_key = keys[index] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
1816
+ " else\n"
1817
+ " frames_key = keys[index] .. \"!c!\" .. sid\n"
1818
+ " end\n"
1819
+ " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
1820
+ " for i = 1, packed_frames_len, 1 do\n"
1821
+ " local packed_frame = redis.call(\"rpop\", frames_key)\n"
1822
+ " local frame = frame_unpackers[index - 1](packed_frame)\n"
1823
+ " if frame then\n"
1824
+ " local count = process_event_and_frame(message, frame, index, use_facts)\n"
1825
+ " result = result + count\n"
1826
+ " if count == 0 or use_facts then\n"
1827
+ " redis.call(\"lpush\", frames_key, packed_frame)\n"
1828
+ " else\n"
1829
+ " break\n"
1830
+ " end\n"
1831
+ " end\n"
1763
1832
  " end\n"
1764
- " sid = current_action[1]\n"
1765
- " name, frame = load_frame_from_sid(sid, max_score)\n"
1766
1833
  " end\n"
1767
- " return sid, name, frame\n"
1768
- "end\n"
1769
- "get_context = function(action_key)\n"
1770
- " if context_directory[action_key] then\n"
1771
- " return context_directory[action_key]\n"
1834
+ " if result == 0 or use_facts then\n"
1835
+ " save_message(index, message, events_key, messages_key)\n"
1772
1836
  " end\n"
1773
- " local input_keys = {[action_key] = true}\n%s"
1774
- "end\n"
1775
- "local new_sid, action_name, frame\n"
1776
- "if #ARGV == 3 then\n"
1777
- " new_sid = ARGV[3]\n"
1778
- " action_name, frame = load_frame_from_sid(new_sid, tonumber(ARGV[2]))\n"
1779
- "else\n"
1780
- " new_sid, action_name, frame = load_frame(tonumber(ARGV[2]))\n"
1837
+ " return result\n"
1781
1838
  "end\n"
1782
- "if frame then\n"
1783
- " redis.call(\"zadd\", action_key, tonumber(ARGV[1]), new_sid)\n"
1784
- " if #ARGV == 2 then\n"
1785
- " local state = redis.call(\"hget\", state_key, new_sid)\n"
1786
- " return {new_sid, state, cjson.encode({[action_name] = frame})}\n"
1787
- " else\n"
1788
- " return {new_sid, cjson.encode({[action_name] = frame})}\n"
1839
+ "local process_key_with_span = function(message, span)\n"
1840
+ " local index = directory[key]\n"
1841
+ " local queue_lock = false\n"
1842
+ " if index then\n"
1843
+ " local last_score = redis.call(\"get\", results_key .. \"!d\")\n"
1844
+ " if not last_score then\n"
1845
+ " redis.call(\"set\", results_key .. \"!d\", score)\n"
1846
+ " else\n"
1847
+ " local new_score = last_score + span\n"
1848
+ " if score > new_score then\n"
1849
+ " redis.call(\"rpush\", results_key, 0)\n"
1850
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1851
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, 0)\n"
1852
+ " local span_count, span_remain = math.modf((score - new_score) / span)\n"
1853
+ " last_score = new_score + span_count * span\n"
1854
+ " redis.call(\"set\", results_key .. \"!d\", last_score)\n"
1855
+ " queue_lock = true\n"
1856
+ " end\n"
1857
+ " end\n"
1858
+ " local count = 0\n"
1859
+ " if not message then\n"
1860
+ " if assert_fact == 0 then\n"
1861
+ " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1862
+ " else\n"
1863
+ " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1864
+ " end\n"
1865
+ " else\n"
1866
+ " if assert_fact == 0 then\n"
1867
+ " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1868
+ " else\n"
1869
+ " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1870
+ " end\n"
1871
+ " end\n"
1872
+ " if (count > 0) then\n"
1873
+ " for i = 1, #results, 1 do\n"
1874
+ " redis.call(\"rpush\", results_key, results[i])\n"
1875
+ " end\n"
1876
+ " end\n"
1789
1877
  " end\n"
1790
- "end\n",
1791
- name,
1792
- name,
1793
- name,
1794
- name,
1795
- name,
1796
- peekActionLua) == -1) {
1797
- return ERR_OUT_OF_MEMORY;
1798
- }
1799
- free(peekActionLua);
1800
- redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
1801
- redisGetReply(reContext, (void**)&reply);
1802
- if (reply->type == REDIS_REPLY_ERROR) {
1803
- printf("%s\n", reply->str);
1804
- freeReplyObject(reply);
1805
- free(lua);
1806
- return ERR_REDIS_ERROR;
1807
- }
1808
-
1809
- strncpy(rulesBinding->peekActionHash, reply->str, 40);
1810
- rulesBinding->peekActionHash[40] = '\0';
1811
- freeReplyObject(reply);
1812
- free(lua);
1813
-
1814
- if (asprintf(&lua,
1815
- "local sid = ARGV[1]\n"
1816
- "local assert_fact = tonumber(ARGV[2])\n"
1817
- "local keys_count = tonumber(ARGV[3])\n"
1818
- "local events_hashset = \"%s!e!\" .. sid\n"
1819
- "local facts_hashset = \"%s!f!\" .. sid\n"
1820
- "local visited_hashset = \"%s!v!\" .. sid\n"
1821
- "local message = {}\n"
1822
- "local primary_message_keys = {}\n"
1823
- "local input_keys = {}\n"
1824
- "local save_message = function(current_key, message, events_key, messages_key)\n"
1825
- " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
1826
- " local primary_key = primary_message_keys[current_key](message)\n"
1827
- " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
1878
+ " return queue_lock\n"
1879
+ "end\n"
1880
+ "local process_key_with_cap = function(message, cap)\n"
1881
+ " local index = directory[key]\n"
1882
+ " local queue_lock = false\n"
1883
+ " if index then\n"
1884
+ " local count = 0\n"
1885
+ " if not message then\n"
1886
+ " if assert_fact == 0 then\n"
1887
+ " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1888
+ " else\n"
1889
+ " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1890
+ " end\n"
1891
+ " else\n"
1892
+ " if assert_fact == 0 then\n"
1893
+ " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1894
+ " else\n"
1895
+ " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1896
+ " end\n"
1897
+ " end\n"
1898
+ " if (count > 0) then\n"
1899
+ " for i = #results, 1, -1 do\n"
1900
+ " redis.call(\"lpush\", results_key, results[i])\n"
1901
+ " end\n"
1902
+ " local diff\n"
1903
+ " local new_count, new_remain = math.modf(#results / cap)\n"
1904
+ " local new_remain = #results %% cap\n"
1905
+ " if new_count > 0 then\n"
1906
+ " for i = 1, new_count, 1 do\n"
1907
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1908
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, cap)\n"
1909
+ " end\n"
1910
+ " end\n"
1911
+ " if new_remain > 0 then\n"
1912
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1913
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, new_remain)\n"
1914
+ " end\n"
1915
+ " if new_count > 0 or new_remain > 0 then\n"
1916
+ " queue_lock = true\n"
1917
+ " end\n"
1918
+ " end\n"
1919
+ " end\n"
1920
+ " return queue_lock\n"
1828
1921
  "end\n"
1829
- "for index = 4 + keys_count, #ARGV, 3 do\n"
1830
- " if ARGV[index + 2] == \"1\" then\n"
1831
- " message[ARGV[index]] = ARGV[index + 1]\n"
1832
- " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
1833
- " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
1834
- " elseif ARGV[index + 2] == \"4\" then\n"
1835
- " if ARGV[index + 1] == \"true\" then\n"
1836
- " message[ARGV[index]] = true\n"
1922
+ "local process_key_with_window = function(message, window)\n"
1923
+ " local index = directory[key]\n"
1924
+ " local queue_lock = false\n"
1925
+ " if index then\n"
1926
+ " local count = 0\n"
1927
+ " if not message then\n"
1928
+ " if assert_fact == 0 then\n"
1929
+ " count = process_inverse_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1930
+ " else\n"
1931
+ " count = process_inverse_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1932
+ " end\n"
1837
1933
  " else\n"
1838
- " message[ARGV[index]] = false\n"
1934
+ " if assert_fact == 0 then\n"
1935
+ " count = process_event(message, index, keys[index] .. \"!e!\" .. sid, false)\n"
1936
+ " else\n"
1937
+ " count = process_event(message, index, keys[index] .. \"!f!\" .. sid, true)\n"
1938
+ " end\n"
1939
+ " end\n"
1940
+ " if (count > 0) then\n"
1941
+ " for i = #results, 1, -1 do\n"
1942
+ " redis.call(\"lpush\", results_key, results[i])\n"
1943
+ " end\n"
1944
+ " local diff\n"
1945
+ " local length = redis.call(\"llen\", results_key)\n"
1946
+ " local prev_count, prev_remain = math.modf((length - count) / window)\n"
1947
+ " local new_count, prev_remain = math.modf(length / window)\n"
1948
+ " diff = new_count - prev_count\n"
1949
+ " if diff > 0 then\n"
1950
+ " for i = 0, diff - 1, 1 do\n"
1951
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, results_key)\n"
1952
+ " if window == 1 then\n"
1953
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"single\")\n"
1954
+ " else\n"
1955
+ " redis.call(\"rpush\", actions_key .. \"!\" .. sid, window)\n"
1956
+ " end\n"
1957
+ " end\n"
1958
+ " queue_lock = true\n"
1959
+ " end\n"
1839
1960
  " end\n"
1840
1961
  " end\n"
1962
+ " return queue_lock\n"
1841
1963
  "end\n"
1842
- "local mid = message[\"id\"]\n"
1843
- "if redis.call(\"hsetnx\", visited_hashset, message[\"id\"], 1) == 0 then\n"
1964
+ "local message = nil\n"
1965
+ "if #ARGV > (6 + keys_count) then\n"
1966
+ " message = {}\n"
1967
+ " for index = 6 + keys_count, #ARGV, 3 do\n"
1968
+ " if ARGV[index + 2] == \"1\" then\n"
1969
+ " message[ARGV[index]] = ARGV[index + 1]\n"
1970
+ " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
1971
+ " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
1972
+ " elseif ARGV[index + 2] == \"4\" then\n"
1973
+ " if ARGV[index + 1] == \"true\" then\n"
1974
+ " message[ARGV[index]] = true\n"
1975
+ " else\n"
1976
+ " message[ARGV[index]] = false\n"
1977
+ " end\n"
1978
+ " end\n"
1979
+ " end\n"
1980
+ " if assert_fact == 1 then\n"
1981
+ " message[\"$f\"] = 1\n"
1982
+ " end\n"
1983
+ "end\n"
1984
+ "if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
1844
1985
  " if assert_fact == 0 then\n"
1845
- " if not redis.call(\"hget\", events_hashset, mid) then\n"
1986
+ " if message and redis.call(\"hexists\", events_hashset, mid) == 0 then\n"
1846
1987
  " return false\n"
1847
1988
  " end\n"
1848
1989
  " else\n"
1849
- " if not redis.call(\"hget\", facts_hashset, mid) then\n"
1990
+ " if message and redis.call(\"hexists\", facts_hashset, mid) == 0 then\n"
1850
1991
  " return false\n"
1851
1992
  " end\n"
1852
1993
  " end\n"
1853
1994
  "end\n"
1854
- "for index = 4, 3 + keys_count, 1 do\n"
1995
+ "for index = 6, 5 + keys_count, 1 do\n"
1855
1996
  " input_keys[ARGV[index]] = true\n"
1856
1997
  "end\n"
1857
- "%sif assert_fact == 1 then\n"
1858
- " message[\"$f\"] = 1\n"
1859
- " for index = 4, 3 + keys_count, 1 do\n"
1860
- " local key = ARGV[index]\n"
1861
- " save_message(key, message, key .. \"!f!\" .. sid, facts_hashset)\n"
1998
+ "%sfor index = 6, 5 + keys_count, 1 do\n"
1999
+ " results = {}\n"
2000
+ " unpacked_results = {}\n"
2001
+ " key = ARGV[index]\n"
2002
+ " context = context_directory[key]\n"
2003
+ " keys = context[\"keys\"]\n"
2004
+ " reviewers = context[\"reviewers\"]\n"
2005
+ " frame_packers = context[\"frame_packers\"]\n"
2006
+ " frame_unpackers = context[\"frame_unpackers\"]\n"
2007
+ " primary_message_keys = context[\"primary_message_keys\"]\n"
2008
+ " primary_frame_keys = context[\"primary_frame_keys\"]\n"
2009
+ " directory = context[\"directory\"]\n"
2010
+ " results_key = context[\"results_key\"]\n"
2011
+ " inverse_directory = context[\"inverse_directory\"]\n"
2012
+ " expressions_count = context[\"expressions_count\"]\n"
2013
+ " local process_key = context[\"process_key\"]\n"
2014
+ " local process_key_count = context[\"process_key_count\"]\n"
2015
+ " queue_action = process_key(message, process_key_count)\n"
2016
+ " if assert_fact == 0 and events_message_cache[tostring(message[\"id\"])] == false then\n"
2017
+ " break\n"
1862
2018
  " end\n"
1863
- "else\n"
1864
- " for index = 4, 3 + keys_count, 1 do\n"
1865
- " local key = ARGV[index]\n"
1866
- " save_message(key, message, key .. \"!e!\" .. sid, events_hashset)\n"
2019
+ "end\n"
2020
+ "if queue_action then\n"
2021
+ " if not redis.call(\"zscore\", actions_key, sid) then\n"
2022
+ " redis.call(\"zadd\", actions_key , score, sid)\n"
1867
2023
  " end\n"
1868
- "end\n",
1869
- name,
1870
- name,
1871
- name,
1872
- addMessageLua) == -1) {
2024
+ "end\n"
2025
+ "return nil\n",
2026
+ name,
2027
+ name,
2028
+ name,
2029
+ name,
2030
+ name,
2031
+ lua) == -1) {
1873
2032
  return ERR_OUT_OF_MEMORY;
1874
2033
  }
1875
2034
 
1876
- free(addMessageLua);
2035
+ free(oldLua);
1877
2036
  redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
1878
2037
  redisGetReply(reContext, (void**)&reply);
1879
2038
  if (reply->type == REDIS_REPLY_ERROR) {
@@ -1883,10 +2042,112 @@ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
1883
2042
  return ERR_REDIS_ERROR;
1884
2043
  }
1885
2044
 
1886
- strncpy(rulesBinding->addMessageHash, reply->str, 40);
1887
- rulesBinding->addMessageHash[40] = '\0';
2045
+ strncpy(rulesBinding->evalMessageHash, reply->str, 40);
2046
+ rulesBinding->evalMessageHash[40] = '\0';
1888
2047
  freeReplyObject(reply);
1889
2048
  free(lua);
2049
+ return RULES_OK;
2050
+ }
2051
+
2052
+ static unsigned int setNames(ruleset *tree, binding *rulesBinding) {
2053
+ char *name = &tree->stringPool[tree->nameOffset];
2054
+ int nameLength = strlen(name);
2055
+ char *sessionHashset = malloc((nameLength + 3) * sizeof(char));
2056
+ if (!sessionHashset) {
2057
+ return ERR_OUT_OF_MEMORY;
2058
+ }
2059
+
2060
+ strncpy(sessionHashset, name, nameLength);
2061
+ sessionHashset[nameLength] = '!';
2062
+ sessionHashset[nameLength + 1] = 's';
2063
+ sessionHashset[nameLength + 2] = '\0';
2064
+ rulesBinding->sessionHashset = sessionHashset;
2065
+
2066
+ char *factsHashset = malloc((nameLength + 3) * sizeof(char));
2067
+ if (!factsHashset) {
2068
+ return ERR_OUT_OF_MEMORY;
2069
+ }
2070
+
2071
+ strncpy(factsHashset, name, nameLength);
2072
+ factsHashset[nameLength] = '!';
2073
+ factsHashset[nameLength + 1] = 'f';
2074
+ factsHashset[nameLength + 2] = '\0';
2075
+ rulesBinding->factsHashset = factsHashset;
2076
+
2077
+ char *eventsHashset = malloc((nameLength + 3) * sizeof(char));
2078
+ if (!eventsHashset) {
2079
+ return ERR_OUT_OF_MEMORY;
2080
+ }
2081
+
2082
+ strncpy(eventsHashset, name, nameLength);
2083
+ eventsHashset[nameLength] = '!';
2084
+ eventsHashset[nameLength + 1] = 'e';
2085
+ eventsHashset[nameLength + 2] = '\0';
2086
+ rulesBinding->eventsHashset = eventsHashset;
2087
+
2088
+ char *timersSortedset = malloc((nameLength + 3) * sizeof(char));
2089
+ if (!timersSortedset) {
2090
+ return ERR_OUT_OF_MEMORY;
2091
+ }
2092
+
2093
+ strncpy(timersSortedset, name, nameLength);
2094
+ timersSortedset[nameLength] = '!';
2095
+ timersSortedset[nameLength + 1] = 't';
2096
+ timersSortedset[nameLength + 2] = '\0';
2097
+ rulesBinding->timersSortedset = timersSortedset;
2098
+ return RULES_OK;
2099
+ }
2100
+
2101
+ static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
2102
+ unsigned int result = loadPartitionCommand(tree, rulesBinding);
2103
+ if (result != RULES_OK) {
2104
+ return result;
2105
+ }
2106
+
2107
+ // client queues have no commands to load,
2108
+ if (!tree->stringPool) {
2109
+ return RULES_OK;
2110
+ }
2111
+
2112
+ result = loadTimerCommand(tree, rulesBinding);
2113
+ if (result != RULES_OK) {
2114
+ return result;
2115
+ }
2116
+
2117
+ result = loadEvalMessageCommand(tree, rulesBinding);
2118
+ if (result != RULES_OK) {
2119
+ return result;
2120
+ }
2121
+
2122
+ result = loadAddMessageCommand(tree, rulesBinding);
2123
+ if (result != RULES_OK) {
2124
+ return result;
2125
+ }
2126
+
2127
+ result = loadPeekActionCommand(tree, rulesBinding);
2128
+ if (result != RULES_OK) {
2129
+ return result;
2130
+ }
2131
+
2132
+ result = loadUpdateActionCommand(tree, rulesBinding);
2133
+ if (result != RULES_OK) {
2134
+ return result;
2135
+ }
2136
+
2137
+ result = loadRemoveActionCommand(tree, rulesBinding);
2138
+ if (result != RULES_OK) {
2139
+ return result;
2140
+ }
2141
+
2142
+ result = loadDeleteSessionCommand(tree, rulesBinding);
2143
+ if (result != RULES_OK) {
2144
+ return result;
2145
+ }
2146
+
2147
+ result = setNames(tree, rulesBinding);
2148
+ if (result != RULES_OK) {
2149
+ return result;
2150
+ }
1890
2151
 
1891
2152
  return RULES_OK;
1892
2153
  }
@@ -2719,6 +2980,34 @@ unsigned int getSession(void *rulesBinding, char *sid, char **state) {
2719
2980
  return REDIS_OK;
2720
2981
  }
2721
2982
 
2983
+ unsigned int deleteSession(void *rulesBinding, char *sid) {
2984
+ binding *currentBinding = (binding*)rulesBinding;
2985
+ redisContext *reContext = currentBinding->reContext;
2986
+
2987
+ int result = redisAppendCommand(reContext,
2988
+ "evalsha %s 0 %s",
2989
+ currentBinding->deleteSessionHash,
2990
+ sid);
2991
+ if (result != REDIS_OK) {
2992
+ return ERR_REDIS_ERROR;
2993
+ }
2994
+
2995
+ redisReply *reply;
2996
+ result = tryGetReply(reContext, &reply);
2997
+ if (result != RULES_OK) {
2998
+ return result;
2999
+ }
3000
+
3001
+ if (reply->type == REDIS_REPLY_ERROR) {
3002
+ printf("deleteSession err string %s\n", reply->str);
3003
+ freeReplyObject(reply);
3004
+ return ERR_REDIS_ERROR;
3005
+ }
3006
+
3007
+ freeReplyObject(reply);
3008
+ return REDIS_OK;
3009
+ }
3010
+
2722
3011
  unsigned int updateAction(void *rulesBinding, char *sid) {
2723
3012
  binding *currentBinding = (binding*)rulesBinding;
2724
3013
  redisContext *reContext = currentBinding->reContext;