durable_rules 0.34.02 → 0.34.03

Sign up to get free protection for your applications and to get access to all the features.
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;