public void Dispose() { // We need to end any pending transactions in the SqLite data access objects lock (_SQLiteFilesMgr_Lock) { if (_SQLiteFiles != null) { for (int idx = _SQLiteFiles.Count - 1; idx >= 0; idx--) { SqLiteDAO nextDBLayer = _SQLiteFiles[idx]; lock (nextDBLayer.ClientCountWantingTransactionToStayOpen_Lock) { nextDBLayer.ClientCountWantingTransactionToStayOpen = 0; nextDBLayer.CommitTransactionSession_ForcedCommit(); try { LogMessage(System.Diagnostics.TraceLevel.Verbose, "SqLite transactions commited and connection closed for: " + nextDBLayer.SqLiteDbPathAndFilename, MethodBase.GetCurrentMethod().DeclaringType.Name + "." + MethodBase.GetCurrentMethod().Name, Thread.CurrentThread.ManagedThreadId); } catch {} } } _SQLiteFiles.Clear(); } _DAO = null; } }
public SqLiteMetadataManager(Boolean AutoCreateDB, UpdateLogCallBack iCallBackDelegate, SqLiteDAO dbAccess, List <TableMetadata> MetadataObjects) { _DBAccess = dbAccess; _MetadataObjects = MetadataObjects; _DefaultUpdateLogCallback = iCallBackDelegate; InitOrCreateDatabase(AutoCreateDB); /*this.DBTableCreatedEvent += new OnDBTableCreated(DBMetadata_DBTableCreatedEvent);*/ }
public void Initialize(string dbFolder, string dbFilenameWithoutPath) { string methodNameForLogging = MethodBase.GetCurrentMethod().DeclaringType.Name + "." + MethodBase.GetCurrentMethod().Name; using (StopWatchProfiler profiler = new StopWatchProfiler("Init Enforcement Actions DB Access (Thread Task)", Logging.LogLevel.Debug, methodNameForLogging, System.Threading.Thread.CurrentThread.ManagedThreadId)) { if (_IsInitialized == true) { throw new Exception("OverstayVioActionDBManager singleton can only be initialized once"); } _IsInitialized = true; _FolderForDatabase = dbFolder; // We're supposed to recieve a filename without path information. But we'll go ahead and fixup if necessary if ((dbFilenameWithoutPath.Contains("\\")) || (dbFilenameWithoutPath.Contains("/"))) { dbFilenameWithoutPath = Path.GetFileName(dbFilenameWithoutPath); } string fullDBLogPathAndFilename = Path.Combine(_FolderForDatabase, dbFilenameWithoutPath); // We need to be thread-safe in this operation lock (_SQLiteFilesMgr_Lock) { foreach (SqLiteDAO nextDBLayer in _SQLiteFiles) { // If we found an item with the same underlying filename, return it if (string.Compare(nextDBLayer.SqLiteDbPathAndFilename, fullDBLogPathAndFilename, true) == 0) { _DAO = nextDBLayer; break; } } // If the desired layer doesn't exist in our list yet, create a new one and add it to the list if (_DAO == null) { string dbConnectStr = string.Format("data source={0}", fullDBLogPathAndFilename); _DAO = new SqLiteDAO(dbConnectStr, fullDBLogPathAndFilename, this.LogMessage); _SQLiteFiles.Add(_DAO); } } // Regardless of if we found an existing DB layer or created a new one, we will perform the DB Metadata check. // (This check will be very quick if it has already been validated, and will block until schema validation is finalized by any thread) // Note that this should be done outside of the "Lock" becasue we only want to lock out other threads when finding/modifying the // list of DB layers -- not when using them. // Before using the database, we need to be sure it has the correct Metadata/Schema information. // We will try to get exclusive access to a variable to see if whether or not the Metadata has been checked. // If we get exclusing access and DB Metadata hasn't been validated yet, we will do so now. if (!Monitor.TryEnter(_DAO.MetadataHasBeenChecked_Lock)) { // Somebody else already has this object locked. Let's immediately record this fact Logging.AddTextToGenericLog(Logging.LogLevel.Debug, "SqLite Metadata check is already locked by another thread. (" + _DefaultDbFilenameWithoutPath + ")", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId); // Now we will do a normal Lock so we are blocked until the Metadata check is finished lock (_DAO.MetadataHasBeenChecked_Lock) { Logging.AddTextToGenericLog(Logging.LogLevel.Debug, "Finished waiting for SqLite Metadata check to complete on different thread. (" + _DefaultDbFilenameWithoutPath + ")", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId); } } else { // The Monitor.TryEnter was successful, so we have a lock on the object. We will need to do Monitor.Exit when done try { if (_DAO.MetadataHasBeenChecked == false) { Logging.AddTextToGenericLog(Logging.LogLevel.Debug, "Acquired exclusive access to verify SqLite Metadata. (" + _DefaultDbFilenameWithoutPath + ")", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId); SqLiteMetadataManager _DBMetadata = new SqLiteMetadataManager(false, LogMessage, _DAO, _Metadata_OverstayVios.Tables); _DBMetadata.CheckAllTables(true); // Set flag so other threads know the Metadata check has already been performed _DAO.MetadataHasBeenChecked = true; // Update Metadata progress log in a thread-safe manner Logging.AddTextToGenericLog(Logging.LogLevel.Debug, "Finished SqLite Metadata verification. (" + _DefaultDbFilenameWithoutPath + ")", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId); } else { Logging.AddTextToGenericLog(Logging.LogLevel.Debug, "No SqLite Metadata check needed -- it's already been performed. (" + _DefaultDbFilenameWithoutPath + ")", System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name + "." + System.Reflection.MethodBase.GetCurrentMethod().Name, System.Threading.Thread.CurrentThread.ManagedThreadId); } } finally { // Set flag so other threads know the Metadata check has already been performed _DAO.MetadataHasBeenChecked = true; // Finally we will do the Monitor.Exit which does the unlocking Monitor.Exit(_DAO.MetadataHasBeenChecked_Lock); } } // Now we need to request DB transaction in the current DB access layer (This should never be done prior to the DB metadata being checked!) // Do a thread-safe increment of the counter to indicate transactions should stay active if (_DAO != null) { lock (_DAO.ClientCountWantingTransactionToStayOpen_Lock) { if (_DAO.ClientCountWantingTransactionToStayOpen == 0) { _DAO.ClientCountWantingTransactionToStayOpen++; // Start a DB session so things are a bit faster in this bulk operation... // (The actual StartTransaction process will depend on how many "listeners" are wanting the transaction to stay active, and current state, etc.) _DAO.StartTransactionSession(); } } } } }