/// <summary>
 ///     Ctor.
 /// </summary>
 /// <param name="startVersion">the first version number to start from</param>
 /// <param name="millisecondLifetimeOldVersions">number of milliseconds a version may hang around before expiry</param>
 /// <param name="timeProvider">provides the current time</param>
 /// <param name="optionalStateHandler">a optional plug-in that may store variable state and retrieve state upon creation</param>
 /// <param name="eventBeanTypedEventFactory">for finding event types</param>
 protected VariableManagementServiceImpl(
     int startVersion,
     long millisecondLifetimeOldVersions,
     TimeProvider timeProvider,
     EventBeanTypedEventFactory eventBeanTypedEventFactory,
     VariableStateNonConstHandler optionalStateHandler)
 {
     this.millisecondLifetimeOldVersions = millisecondLifetimeOldVersions;
     this.timeProvider = timeProvider;
     this.eventBeanTypedEventFactory = eventBeanTypedEventFactory;
     OptionalStateHandler = optionalStateHandler;
     DeploymentsWithVariables = new Dictionary<string, VariableDeployment>().WithNullKeySupport();
     ReadWriteLock = new SlimReaderWriterLock(60000);
     variableVersionsPerCP = new List<ConcurrentDictionary<int, VariableReader>>();
     changeCallbacksPerCP = new List<IDictionary<int, ICollection<VariableChangeCallback>>>();
     currentVersionNumber = startVersion;
 }
        private static void TryChainedCountSum(
            RegressionEnvironment env,
            int numThreads,
            int numEvents)
        {
            // setup statements
            var path = new RegressionPath();
            env.CompileDeploy("insert into MyStreamOne select count(*) as cnt from SupportBean", path);
            env.CompileDeploy("@Name('s0') insert into MyStreamTwo select sum(cnt) as mysum from MyStreamOne", path);
            var listener = new SupportUpdateListener();
            env.Statement("s0").AddListener(listener);

            // execute
            var threadPool = Executors.NewFixedThreadPool(
                numThreads,
                new SupportThreadFactory(typeof(MultithreadDeterminismInsertInto)).ThreadFactory);
            var future = new IFuture<object>[numThreads];
            IReaderWriterLock sharedStartLock = new SlimReaderWriterLock();
            using (sharedStartLock.WriteLock.Acquire()) {
                for (var i = 0; i < numThreads; i++) {
                    future[i] = threadPool.Submit(
                        new SendEventRWLockCallable(
                            i,
                            sharedStartLock,
                            env.Runtime,
                            new GeneratorEnumerator(numEvents)));
                }

                SupportCompileDeployUtil.ThreadSleep(100);
            }

            threadPool.Shutdown();
            SupportCompileDeployUtil.ExecutorAwait(threadPool, 10, TimeUnit.SECONDS);
            SupportCompileDeployUtil.AssertFutures(future);

            // assert result
            var newEvents = listener.NewDataListFlattened;
            for (var i = 0; i < numEvents - 1; i++) {
                var expected = Total(i + 1);
                Assert.AreEqual(expected, newEvents[i].Get("mysum"));
            }

            env.UndeployAll();
        }
        private static void TrySendCountFollowedBy(
            int numThreads,
            int numEvents,
            Locking locking,
            Configuration configuration)
        {
            configuration.Runtime.Threading.InsertIntoDispatchLocking = locking;
            configuration.Runtime.Threading.InsertIntoDispatchTimeout = 5000; // 5 second timeout
            configuration.Common.AddEventType(typeof(SupportBean));

            // This should fail all test in this class
            // config.getEngineDefaults().getThreading().setInsertIntoDispatchPreserveOrder(false);
            var runtime = EPRuntimeProvider.GetRuntime(
                typeof(MultithreadDeterminismInsertIntoLockConfig).Name,
                configuration);
            runtime.Initialize();

            // setup statements
            var path = new RegressionPath();
            var eplInsert = "insert into MyStream select count(*) as cnt from SupportBean";
            var compiledInsert = Compile(eplInsert, configuration, path);
            path.Add(compiledInsert);
            var deployedInsert = Deploy(compiledInsert, runtime);
            deployedInsert.Statements[0].Events += (
                sender,
                updateEventArgs) => {
                log.Debug(".update cnt=" + updateEventArgs.NewEvents[0].Get("cnt"));
            };

            var listeners = new SupportUpdateListener[numEvents];
            for (var i = 0; i < numEvents; i++) {
                var text = "select * from pattern [MyStream(cnt=" + (i + 1) + ") -> MyStream(cnt=" + (i + 2) + ")]";
                var compiled = Compile(text, configuration, path);
                var deployedPattern = Deploy(compiled, runtime);
                listeners[i] = new SupportUpdateListener();
                deployedPattern.Statements[0].AddListener(listeners[i]);
            }

            // execute
            var threadPool = Executors.NewFixedThreadPool(
                numThreads,
                new SupportThreadFactory(typeof(MultithreadDeterminismInsertIntoLockConfig)).ThreadFactory);
            var future = new IFuture<object>[numThreads];
            var sharedStartLock = new SlimReaderWriterLock();
            using (sharedStartLock.WriteLock.Acquire()) {
                for (var i = 0; i < numThreads; i++) {
                    future[i] = threadPool.Submit(
                        new SendEventRWLockCallable(i, sharedStartLock, runtime, new GeneratorEnumerator(numEvents)));
                }

                ThreadSleep(100);
            }

            threadPool.Shutdown();
            ExecutorAwait(threadPool, 10, TimeUnit.SECONDS);
            AssertFutures(future);

            // assert result
            for (var i = 0; i < numEvents - 1; i++) {
                Assert.AreEqual(1, listeners[i].NewDataList.Count, "Listener not invoked: #" + i);
            }

            runtime.Destroy();
        }
        private static void TryMultiInsertGroup(
            RegressionEnvironment env,
            int numThreads,
            int numStatements,
            int numEvents)
        {
            // This should fail all test in this class
            // config.getEngineDefaults().getThreading().setInsertIntoDispatchPreserveOrder(false);

            // setup statements
            var path = new RegressionPath();
            var insertIntoStmts = new EPStatement[numStatements];
            for (var i = 0; i < numStatements; i++) {
                var epl = $"@Name('s{i}') insert into MyStream select {i} as ident,count(*) as cnt from SupportBean";
                insertIntoStmts[i] = env.CompileDeploy(epl, path).Statement("s" + i);
            }

            env.CompileDeploy("@Name('final') select ident, sum(cnt) as mysum from MyStream group by ident", path);
            var listener = new SupportMTUpdateListener();
            env.Statement("final").AddListener(listener);

            // execute
            var threadPool = Executors.NewFixedThreadPool(
                numThreads,
                new SupportThreadFactory(typeof(MultithreadDeterminismInsertInto)).ThreadFactory);
            var future = new IFuture<object>[numThreads];
            var sharedStartLock = new SlimReaderWriterLock();
            using (sharedStartLock.WriteLock.Acquire()) {
                for (var i = 0; i < numThreads; i++) {
                    future[i] = threadPool.Submit(
                        new SendEventRWLockCallable(
                            i,
                            sharedStartLock,
                            env.Runtime,
                            new GeneratorEnumerator(numEvents)));
                }

                SupportCompileDeployUtil.ThreadSleep(100);
            }

            threadPool.Shutdown();
            SupportCompileDeployUtil.ExecutorAwait(threadPool, 10, TimeUnit.SECONDS);
            SupportCompileDeployUtil.AssertFutures(future);

            // assert result
            var newEvents = listener.GetNewDataListFlattened();
            IList<long>[] resultsPerIdent = new List<long>[numStatements];
            foreach (var theEvent in newEvents) {
                var ident = theEvent.Get("ident").AsInt32();
                if (resultsPerIdent[ident] == null) {
                    resultsPerIdent[ident] = new List<long>();
                }

                var mysum = theEvent.Get("mysum").AsInt64();
                resultsPerIdent[ident].Add(mysum);
            }

            for (var statement = 0; statement < numStatements; statement++) {
                for (var i = 0; i < numEvents - 1; i++) {
                    var expected = Total(i + 1);
                    Assert.AreEqual(
                        expected,
                        resultsPerIdent[statement][i],
                        "Failed for statement " + statement);
                }
            }

            env.UndeployAll();
        }