public void UpdateBeingCollectedProperly()
        {
            using (FileDeleter fd = new FileDeleter(Extensions.GetTempDBFile()))
            {
                Database db = new Database(new Context(fd.Fi));
                using (SQLiteConnection conn = db.Connection)
                {
                    conn.Open();
                    Initializer init = new Initializer(null);
                    init.Initialize(db);

                    Tuple <List <DeviceInfo>, DateTimeOffset> devices = LoadDevices(db, conn);

                    TimeSpan one_second = TimeSpan.FromSeconds(1);
                    DBCollectionTimeRetriever retriever = new DBCollectionTimeRetriever(conn);

                    foreach (long collector_id in retriever.AllIDs)
                    {
                        string sql = $"SELECT LastCollectionAttempt, LastCollectedAt, NextCollectionTime, CurrentlyBeingCollected, FrequencyInMinutes FROM Collectors WHERE CollectorID = {collector_id}";
                        using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                            using (SQLiteDataReader reader = command.ExecuteReader())
                            {
                                if (reader.Read())
                                {
                                    // Before being collected, the CurrentlyBeingCollected column should have 0
                                    Assert.True(reader.IsDBNull(0));
                                    Assert.True(reader.IsDBNull(1));
                                    Assert.True(reader.IsDBNull(2));
                                    Assert.False(reader.IsDBNull(3));
                                    Assert.Equal(0, reader.GetInt32(3));
                                    Assert.False(reader.IsDBNull(4));
                                }
                            }

                        using (BeingCollected bc = new BeingCollected(collector_id, conn))
                        {
                            using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                                using (SQLiteDataReader reader = command.ExecuteReader())
                                {
                                    if (reader.Read())
                                    {
                                        // Now that it's being collected, the LastCollectionAttempt and NextCollectionTime columns
                                        // should have something there, and the CurrentlyBeingCollected column should have 1
                                        Assert.False(reader.IsDBNull(0));
                                        Assert.True(reader.IsDBNull(1));
                                        Assert.False(reader.IsDBNull(2));
                                        Assert.False(reader.IsDBNull(3));
                                        Assert.Equal(1, reader.GetInt32(3));

                                        if (DateTimeOffset.TryParse(reader.GetString(0), out DateTimeOffset lca))
                                        {
                                            // Make sure it just happened...let's say within 1 second of now
                                            DateTimeOffset now   = DateTimeOffset.Now;
                                            DateTimeOffset lower = now - one_second;
                                            Assert.InRange(lca, lower, now);

                                            // And make sure NextCollectionTime is correct--lets just see if the time is
                                            // in the future.
                                            int frequency = reader.GetInt32(4);
                                            if (frequency > 0 && DateTimeOffset.TryParse(reader.GetString(2), out DateTimeOffset next))
                                            {
                                                Assert.True(next >= now);
                                            }
                                        }
                                        else
                                        {
                                            Assert.True(false);
                                        }
                                    }
                                }
                        }

                        using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                            using (SQLiteDataReader reader = command.ExecuteReader())
                            {
                                if (reader.Read())
                                {
                                    // And after being collected, the CurrentlyBeingCollected column should have 0 again
                                    Assert.False(reader.IsDBNull(0));
                                    Assert.True(reader.IsDBNull(1));
                                    Assert.False(reader.IsDBNull(2));
                                    Assert.False(reader.IsDBNull(3));
                                    Assert.Equal(0, reader.GetInt32(3));
                                }
                            }

                        // The LastCollectedAt column should remain NULL because it's set when the data is stored and
                        // we didn't store anything here.
                    }

                    // Now make sure none of them show as being collected
                    foreach (long collector_id in retriever.AllIDs)
                    {
                        string sql = $"SELECT CurrentlyBeingCollected FROM Collectors WHERE CollectorID = {collector_id}";
                        using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                            using (SQLiteDataReader reader = command.ExecuteReader())
                            {
                                if (reader.Read())
                                {
                                    Assert.Equal(0, reader.GetInt32(0));
                                }
                            }
                    }

                    // And make sure that if an exception occurs while marking it as being collected that it shows as
                    // no longer being collected
                    foreach (long collector_id in retriever.AllIDs)
                    {
                        string sql = $"SELECT CurrentlyBeingCollected FROM Collectors WHERE CollectorID = {collector_id}";
                        try
                        {
                            using (BeingCollected bc = new BeingCollected(collector_id, conn))
                            {
                                using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                                    using (SQLiteDataReader reader = command.ExecuteReader())
                                    {
                                        if (reader.Read())
                                        {
                                            Assert.Equal(1, reader.GetInt32(0));
                                        }
                                    }
                                throw new Exception($"Exception with collector_id {collector_id}");
                            }
                        }
                        catch (Exception)
                        {
                        }

                        using (SQLiteCommand command = new SQLiteCommand(sql, conn))
                            using (SQLiteDataReader reader = command.ExecuteReader())
                            {
                                if (reader.Read())
                                {
                                    Assert.Equal(0, reader.GetInt32(0));
                                }
                            }
                    }
                }
            }
        }
示例#2
0
        protected void ThreadFunc()
        {
            try
            {
                int max_collections_per_pass = 10;
                logging.EventLog elog        = new ApplicationEventLog();
                Database         db          = new Database();
                DataStorage      storage     = new DataStorage();
                m_interpreters.ForEach(i => storage.AddInterpreter(i));

                while (GlobalIsRunning.IsRunning)
                {
                    int collector_count = 0;

                    using (SQLiteConnection conn = db.Connection)
                    {
                        conn.Open();

                        CheckForConfigurationChanges(storage, conn);

                        // Used to hold which collector was doing its thing if/when an exception occurs.
                        // It's used in the exception handler.
                        string collector_name = string.Empty;

                        try
                        {
                            DBCollectionTimeRetriever retriever = new DBCollectionTimeRetriever(conn);

                            // Gets the list of things that need to be collected right now. They'll
                            // be in the order they should be collected.
                            List <DataCollector> collectors = m_system_device.GetCollectors(retriever);
                            collector_count = collectors.Count;

                            // Limit this to the top 10 or so
                            while (collectors.Count > max_collections_per_pass)
                            {
                                collectors.RemoveAt(collectors.Count - 1);
                            }

                            foreach (DataCollector collector in collectors)
                            {
                                collector_name = collector.Context.Name;
                                //elog.LogInformation($"Collecting {collector_name}");

                                Stopwatch watch = Stopwatch.StartNew();

                                // Records that the collector is being collected, updates the next collection
                                // time, and records when the collection attempt was started. When it's destroyed
                                // when exiting the using, it records that it is no longer being collected.
                                //
                                // This was done so even if an exception occurs within Acquire(), the flag
                                // that the collector is being collected will be cleared.
                                using (BeingCollected bc = new BeingCollected(collector.Context.ID.ID, conn))
                                {
                                    collector.Acquire();
                                }

                                //long elapsed_ms = watch.ElapsedMilliseconds;
                                //if(elapsed_ms > 500)
                                //    elog.LogInformation($"Collecting {collector_name} took {elapsed_ms} ms");

                                if (GlobalIsRunning.IsRunning == false)
                                {
                                    break;  // out of the foreach loop
                                }
                            }
                        }
                        catch (Exception e)
                        {
                            elog.LogError($"Exception from within {collector_name}");
                            elog.Log(e);
                        }

                        // Will write the daily file when it's the right time to do so; otherwise, it does nothing.
                        if (GlobalIsRunning.IsRunning)
                        {
                            m_daily_file_writer.DoWrite(conn);
                        }

                        if (GlobalIsRunning.IsRunning)
                        {
                            m_db_cleaner.CleanOldData(m_days_to_keep, conn);
                        }
                    }

                    // Deletes any old daily files
                    if (GlobalIsRunning.IsRunning)
                    {
                        m_daily_file_cleaner.DoClean();
                    }

                    // Delete any old log files too, if it's time to do so.
                    if (GlobalIsRunning.IsRunning)
                    {
                        LogManager.CleanOldData();
                    }

                    // And make sure we update our logging if it changed
                    if (GlobalIsRunning.IsRunning)
                    {
                        LogManager.CheckConfiguration();
                    }

                    // m_shutdown will be reset when the thread starts, and set when it's time to
                    // stop the thread. So this will wait if this event hasn't been
                    // set, but will return immediately if it has been set.
                    //
                    // If there's still more data to collect let's make another run right away
                    if (GlobalIsRunning.IsRunning && collector_count < max_collections_per_pass)
                    {
                        m_shutdown.WaitOne(TimeSpan.FromSeconds(10));
                    }
                }

                m_interpreters.ForEach(i => storage.RemoveInterpreter(i));
            }
            catch (Exception e)
            {
                logging.EventLog elog = new ApplicationEventLog();
                elog.Log(e);

                m_shutdown.Reset();
                m_thread.Abort();
                m_thread = null;
            }
        }