Drools Fusion time sliding based windows - drools

I cannot undestand how JBoss Drools inference engine works with complex event processing (drools fusion). Actually i created a rule in order to deny a transaction if more than 2 transactions occour in less than 5 seconds. Here is the rule
rule "more than 2 transaction in 5 seconds"
when
$transaction : Transaction( $id : id )
Number(intValue > 2) from accumulate(
$t : Transaction() over window:time(5s),
count($t))
then
$transaction.setDenied(true);
end
I set the session in streaming mode using the pseudo session clock.
Here the java code
SessionPseudoClock clock = kSession.getSessionClock();
Transaction tx1 = new Transaction(new BigInteger("10000"), TransactionType.CREDIT_CARD, 1L);
Transaction tx2 = new Transaction(new BigInteger("2000"), TransactionType.CREDIT_CARD,2L);
Transaction tx3 = new Transaction(new BigInteger("50000"), TransactionType.DEPOSIT,3L);
Transaction tx4 = new Transaction(new BigInteger("100"), TransactionType.WITHDRAW,4L);
assertTransaction(kSession, tx1);
clock.advanceTime(6, TimeUnit.SECONDS);
assertTransaction(kSession, tx2);
clock.advanceTime(3, TimeUnit.SECONDS);
assertTransaction(kSession, tx3);
clock.advanceTime(1800, TimeUnit.MILLISECONDS);
assertTransaction(kSession, tx4);
where assertTransaction simple contains the following code:
kSession.insert(tx);
kSession.fireAllRules();
The transaction that trigger the rule match is the tx4 since tx2 happen 6 seconds after tx1 and tx1 fall out the timed window. The strange thing is that the action of the rule is executed for all the transaction in the working memory, even for tx1.
Is it supposed to work in this way?
Thanks in advance

The main issue is that the Engine isn't given a chance to execute pending activations and to process facts according to the current reading of the (pseudo) clock. Also, the rule will fire for each Transaction currently in working memory while you expect it to fire for the latest transaction only.
With CEP, test or production, I recommend to run the Engine in a separate thread, calling fireUntilHalt. Then, for test or production, one can use the real clock and insert facts as they come or from a thread that pauses between insertions. And the pseudo clock can be used as well, almost without any change in the code.
To ensure that the rule fires only for the most recent thread, change the rule to
rule "more than 2 transaction in 5 seconds"
when
$transaction : Transaction( $id : id )
not Transaction( this after $transaction )
Number(intValue > 2) from accumulate(
$t : Transaction() over window:time(5s),
count($t))
then
System.out.println( "denied: " + $transaction );
end

Related

DB2 measure execution time of triggers

How can I best measure the execution time of triggers in DB2 for insert or update.
It is needed for some performance issues, some of them are behaving very slow.
CREATE OR REPLACE TRIGGER CHECK
NO CASCADE BEFORE INSERT ON DAG
REFERENCING NEW AS OBJ
FOR EACH ROW MODE DB2SQL
WHEN(
xyz)
)
SIGNAL SQLSTATE xxx)
For compiled triggers (that is, with BEGIN ... END body):
SELECT
T.TRIGNAME
, M.SECTION_NUMBER
, M.STMT_EXEC_TIME
, M.NUM_EXEC_WITH_METRICS
-- Other M metrics
, M.*
, M.STMT_TEXT
FROM SYSCAT.TRIGGERS T
JOIN SYSCAT.TRIGDEP D
ON (D.TRIGSCHEMA, D.TRIGNAME) = (T.TRIGSCHEMA, T.TRIGNAME)
JOIN TABLE (MON_GET_PKG_CACHE_STMT (NULL, NULL, NULL, -2)) M
ON (M.PACKAGE_SCHEMA, M.PACKAGE_NAME) = (D.BSCHEMA, D.BNAME)
WHERE D.BTYPE = 'K'
-- Or use whatever filter on your triggers
AND (T.TABSCHEMA, T.TABNAME) = ('MYSCHEMA', 'MYTABLE')
ORDER BY 1, 2
For inlined triggers (that is, with BEGIN ATOMIC ... END body):
No way to get separate statistics for them. They are compiled and optimized with the corresponding statement fired them.

I want to remove objects from working memory EXCEPT for one specific one

Using Drools 5.5.FINAL. I have a rule that detects when there is exactly one ACTIVE Contract record from among multiple Contract records in working memory.
/**
* There is exactly ONE Active Contract
*/
rule "Exactly one ACTIVE among multiple"
salience 870
activation-group "BRValidation"
no-loop
when
$bmsContract : BMSContract( STAT_CD == BMS_Contract_Status.ACTIVE.toString() )
not BMSContract( this != $bmsContract, STAT_CD == BMS_Contract_Status.ACTIVE.toString() )
$blueReport : BlueReport( status == null )
then
logger.info("Rule detected one ACTIVE record from among multiple contracts;" + " Rule=" + drools.getRule().getName());
modify ( $blueReport ) {
setStatus( BlueReportStatus.SUCCESSFUL.toString() ),
setReason( "Single ACTIVE status among many contracts - that's OK"),
appendRuleAudit(drools.getRule().getName());
}
end
What I need to do in the RHS is to remove all instances of BMSContract object except for the one that has "ACTIVE" STAT_CD. How can I do that?

Entity Framework Takes a longer time to get the response the first time using within the same context

I am having an issues with the EF that the first query takes a long time. I thought the query itself was taking a long time. So, I used
context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
to see what query is being sent. It only took only 1 ms but from the open connection to close connection, it took 18 second. The following is the message from the debug message.
**Opened connection at 3/19/2015 9:25:49 PM +06:30
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ItemId] AS [ItemId],
[Extent1].[SerialNumber] AS [SerialNumber],
[Extent1].[SimNumber] AS [SimNumber],
[Extent1].[ItemStatusId] AS [ItemStatusId],
[Extent1].[StoreId] AS [StoreId]
FROM [dbo].[ItemDetail] AS [Extent1]
-- Executing at 3/19/2015 9:25:49 PM +06:30
-- Completed in 1 ms with result: SqlDataReader
Closed connection at 3/19/2015 9:26:07 PM +06:30**
Within the same context, another query similar to the previous one was sent. It only took 1 second from the Open to Close connection.
**Opened connection at 3/19/2015 9:26:10 PM +06:30
SELECT
[Extent1].[Id] AS [Id],
[Extent1].[ItemId] AS [ItemId],
[Extent1].[SerialNumber] AS [SerialNumber],
[Extent1].[SimNumber] AS [SimNumber],
[Extent1].[ItemStatusId] AS [ItemStatusId],
[Extent1].[StoreId] AS [StoreId]
FROM [dbo].[ItemDetail] AS [Extent1]
INNER JOIN [dbo].[Item] AS [Extent2] ON [Extent1].[ItemId] = [Extent2].[Id]
WHERE ([Extent1].[ItemStatusId] = #p__linq__0) AND ([Extent2].[CategoryId] = #p__linq__1) AND ([Extent1].[StoreId] = #p__linq__2)
-- p__linq__0: '1' (Type = Int32, IsNullable = false)
-- p__linq__1: '2' (Type = Int32, IsNullable = false)
-- p__linq__2: '1' (Type = Int32, IsNullable = false)
-- Executing at 3/19/2015 9:26:10 PM +06:30
-- Completed in 1 ms with result: SqlDataReader
Closed connection at 3/19/2015 9:26:11 PM +06:30**
Why does the first query take longer time to close the connection?
I know that the first query usually take time because of loading the meta data. But this is different that the open connection and executing query are so close and after getting the results, it takes a long time to close the connection in the first query.
Without knowing more details of your code, the only factor I can come up with is that it matters how a LINQ query is processed. One thing in particular that can cause a connection to remain open relatively long is enumerating a LINQ query and executing some time-consuming process in each iteration:
var details = from d in ItemDetail
where ...
select new { ... }
foreach (var detail in details)
{
// DbDataReader reads a record on each iteration
SomeLengthyProcess(detail);
}
// Connection is closed after the last iteration.
Here's a sample output (leaving out some irrelevant details)
Opened connection at 09:48:33
SELECT statement
-- Executing at 09:48:33
-- Completed in 14 ms with result: SqlDataReader
Record1
Record2
Record3
Record4
Record5
Closed connection at 09:48:37
Which shows that the statement itself is executed in "no time", but that it takes another 4s for the reader to produce each record.
The way to make the connection close sooner is:
foreach (var detail in details.ToList())
which builds an in-memory list first and then iterates over it. In this case, the connection closes immediately after the "Completed" logging line.

Count number of facts in working memory

I need to count the number of facts satisfying a certain constraint in working memory and then fire the rule if the number of facts breaches a certain threshold. I tried the following but it is complaining about "mismatched input '$cnt' in rule "Rule1"
rule Rule1
when
accumulate ( AFact ( code == "XXXX" ); $cnt : count(1) ; $cnt > 1 )
then
// fire
end
Any help to get the syntax right would be appreciated. Thanks!
The accumulate Conditional Element (as you are using) is only available in Drools versions 5.4 and later - you must be using 5.3.0 or earlier.
You can use the old form of accumulate, available as a continuation of from:
Number( intValue > 1 )
from accumulate( AFact ( code == "XXXX" ), count(1) )

Deadlock between select and truncate (postgresql)

Table output_values_center1 (and some other) inherits output_values. Periodically I truncate table output_values_center1 and load new data (in one transaction). In that time user can request some data and he got error message. Why it ever happens (select query requests only one record) and how to avoid such problem:
2010-05-19 14:43:17 UTC ERROR: deadlock detected
2010-05-19 14:43:17 UTC DETAIL: Process 25972 waits for AccessShareLock on relation 2495092 of database 16385; blocked by process 26102.
Process 26102 waits for AccessExclusiveLock on relation 2494865 of database 16385; blocked by process 25972.
Process 25972: SELECT * FROM "output_values" WHERE ("output_values".id = 122312) LIMIT 1
Process 26102: TRUNCATE TABLE "output_values_center1"
"TRUNCATE acquires an ACCESS EXCLUSIVE lock on each table it operates on, which blocks all other concurrent operations on the table. If concurrent access to a table is required, then the DELETE command should be used instead."
Obviously it's not clear if you just look at the "manpage" linked above why querying the parent table affects its descendant. The following excerpt from the "manpage" for the SELECT command clarifies it:
"If ONLY is specified, only that table is scanned. If ONLY is not specified, the table and any descendant tables are scanned."
I'd try this (in pseudocode) for truncating:
#define NOWAIT_TIMES 100
#define SLEEPTIME_USECS (1000*100)
for ( i=0; ; i++ ) {
ok = query('start transaction');
if ( !ok ) raise 'Unable to start transaction!';
queries = array(
'lock table output_values in access exclusive mode nowait',
'truncate output_values_center1',
'commit'
);
if ( i>NOWAIT_TIMES ) {
// we will wait this time, as we tried NOWAIT_TIMES and failed
queries[0] = 'lock table output_values in access exclusive mode';
}
foreach q in queries {
ok = query(q);
if (!ok) break;
}
if (!ok) {
query('rollback');
usleep(SLEEPTIME_USECS);
} else {
break;
};
};
This way you'll be safe from deadlocks, as parent table will be exclusively locked. A user will just block for a fraction of second while truncate runs and will automatically resume after commit.
But be prepared that this can run several seconds on busy server as when table is in use then lock will fail and be retried.