}//ProcessQuery() // private void ProcessWriteQuery(Queries.QueryBase query, MySqlConnection mySqlConnection) { try { string cmdString = query.GetQuery(m_Database); Log.NewEntry(LogLevel.Minor, "ProcessQuery: {0}", cmdString); if (string.IsNullOrEmpty(cmdString)) { Log.NewEntry(LogLevel.Major, "ProcessQuery: Query provided is empty."); query.Status = Queries.QueryStatus.Failed; OnQueryResponse((EventArgs)query); } MySqlCommand cmd = new MySqlCommand(cmdString, mySqlConnection); int nRows = cmd.ExecuteNonQuery(); query.Status = Queries.QueryStatus.Completed; } catch (Exception e) { Log.NewEntry(LogLevel.Major, "ProcessQuery: {1} exception: {0}", e.Message, query); query.ErrorMessage = e.Message; query.Status = Queries.QueryStatus.Failed; } // // This is complete. Push onto the queue. // this.HubEventEnqueue(query); }//ProcessQuery()
}// Start() // // // ***************************************** // **** SubmitAsync() **** // ***************************************** /// <summary> /// This is the asynchronous query. The requesting thread is /// immediately released after pushing the query request onto the /// hub queue, and call back is made with a QueryResponse event. /// The results as placed withing the query object, so the calling /// thread should not keep it. /// </summary> /// <param name="request"></param> public void SubmitAsync(Queries.QueryBase request) { if (!((int)m_ServiceState >= (int)ServiceStates.Stopping)) { // Regardless of the type of query (read or write), the request // is simply pushed onto the queue. this.HubEventEnqueue((EventArgs)request); } else { request.Status = Queries.QueryStatus.Failed; request.ErrorMessage = "DatabaseReaderWriter shutting down."; OnQueryResponse((EventArgs)request); } }//SubmitAsync()
}//SubmitAsync() // // // // // ***************************************** // **** SubmitSync() **** // ***************************************** /// <summary> /// Here, the query is made synchronously and the requesting /// thread waits until the query is completed, the results are /// added to the query and returned to the calling thread. /// No event is triggered in this case. /// /// NOTE: This only works correctly with read queries. Write queries are always queued. /// </summary> /// <param name="request"></param> /// <returns></returns> public bool SubmitSync(Queries.QueryBase request) { bool isSuccessful = false; if ((int)m_ServiceState >= (int)ServiceStates.Stopping) { request.Status = Queries.QueryStatus.Failed; request.ErrorMessage = "DatabaseReaderWriter shutting down."; return(false); } // if (request.IsRead) { // This request is a query, which will have data returned to it. // All such requests will be done be the main thread for this hub. // (This keeps all query work spaces lock free for the main thread, but the // caller will need to wait a bit more.) // Now, create a waithandle to block the calling thread until data is ready. EventWaitHandle wh = null; if (!m_WaitHandleFactory.TryDequeue(out wh)) { wh = new EventWaitHandle(false, EventResetMode.AutoReset); } m_WaitHandles.TryAdd(request.QueryID, wh); // leave my phone number here, with the query I am waiting for. this.HubEventEnqueue((EventArgs)request); // submit request wh.WaitOne(); // wait for callback here. EventWaitHandle wh2; // Try to recycle my wait handle. if (m_WaitHandles.TryRemove(request.QueryID, out wh2)) // They can been removed by other threads in bad cases; e.g., ShutdownNow() { m_WaitHandleFactory.Enqueue(wh2); // Usually, we get our own wait handle (same as wh above), except during shutdowns, etc. } isSuccessful = (request.Status != Queries.QueryStatus.Failed); } else { // This is a write, which the thread can do for himself, if he likes. } // Exit return(isSuccessful); }//SubmitAsync()
}//HubEventHandler() // // // ************************************************* // **** ProcessQuery(iQuery) **** // ************************************************* private void ProcessReadQuery(Queries.QueryBase query) { MySqlConnection mySqlConnection = null; // Try to connect if (!m_Database.IsTryToConnect(ref mySqlConnection)) { // Failed to connect. Log.NewEntry(LogLevel.Major, "ProcessQuery: Failed to connect to {0}.", m_Database); query.Status = Queries.QueryStatus.Failed; OnQueryResponse((EventArgs)query); } // MySqlDataReader reader = null; try { string cmdString = query.GetQuery(m_Database); Log.NewEntry(LogLevel.Minor, "ProcessQuery: {0}", cmdString); if (string.IsNullOrEmpty(cmdString)) { Log.NewEntry(LogLevel.Major, "ProcessQuery: Query provided is empty."); query.Status = Queries.QueryStatus.Failed; OnQueryResponse((EventArgs)query); } MySqlCommand cmd = new MySqlCommand(cmdString, mySqlConnection); reader = cmd.ExecuteReader(); int fieldCount = reader.FieldCount; List <string> fieldNames = new List <string>(); // place to store column names List <object> values = new List <object>(); // place to store values. Count will be (fieldCount * nRows) for (int i = 0; i < fieldCount; ++i) { fieldNames.Add(reader.GetName(i)); } while (reader.Read()) { // Reading the next row for (int i = 0; i < fieldCount; ++i) { // Read the ith column in this row. if (reader.IsDBNull(i)) { values.Add(null); continue; } Type type = reader.GetFieldType(i); if (type == typeof(int)) { values.Add(reader.GetInt32(i)); } else if (type == typeof(double)) { values.Add(reader.GetDouble(i)); } else { object o = reader.GetValue(i); values.Add(o); } }//next ith column. } // Give the data to the query. query.Status = query.AcceptData(m_Database, values, fieldNames); } catch (Exception e) { Log.NewEntry(LogLevel.Major, "ProcessQuery: {1} exception: {0}", e.Message, query); query.ErrorMessage = e.Message; query.Status = Queries.QueryStatus.Failed; } if (reader != null && reader.IsClosed == false) { try { reader.Close(); } catch (Exception e) { Log.NewEntry(LogLevel.Major, "ProcessQuery: Closing reader {1} exception: {0}", e.Message, query); } } if (mySqlConnection != null) { mySqlConnection.Close(); } // // This is complete. Push onto the queue. // this.HubEventEnqueue(query); }//ProcessQuery()
}// RequestStop() // // // // // // // #endregion//Public Methods #region Private Hub Event Handler Methods // ***************************************************************** // **** Private Methods **** // ***************************************************************** // // // // // ************************************************* // **** HubEvent Handler() **** // ************************************************* /// <summary> /// This is the main processing routine. /// </summary> /// <param name="eventArgsList"></param> protected override void HubEventHandler(EventArgs[] eventArgsList) { if (m_ServiceState == ServiceStates.Unstarted || m_ServiceState == ServiceStates.Started) { m_ServiceState = ServiceStates.Running; OnServiceStateChanged(ServiceStates.Unstarted, ServiceStates.Started); OnServiceStateChanged(ServiceStates.Started, ServiceStates.Running); } // // // foreach (EventArgs eventArg in eventArgsList) { if (eventArg == null || eventArg == EventArgs.Empty) { continue; } if (eventArg is Queries.QueryBase) { Queries.QueryBase query = (Queries.QueryBase)eventArg; if (query.QueryID == 6) { } if (query.Status == Queries.QueryStatus.New) { // This is a new query request, for either read or write. // We will process this query here. if (query.IsRead) { // If the user has requested a "query" then he probably // expects to receive an answer, and so this we try to carry out immediately. ProcessReadQuery(query); } else { // User wants to write data. m_WriteQueryQueue.Enqueue(query); } } else { // This is a query that we have already processed. // It has been pushed back onto the queue to be returned to the caller. EventWaitHandle wh = null; if (m_WaitHandles.TryRemove(query.QueryID, out wh)) { // If this queryID has a wait handle, then the creator has made a synchronized // call and is waiting for the response at the wait handle. wh.Set(); // Wake the caller now (he has a copy of the query). m_WaitHandleFactory.Enqueue(wh); // No need to trigger an event in this case, recycle the wait handle. } else { OnQueryResponse((EventArgs)query); // Here, the caller has made async call. So we must trigger event for him. } } } else if (eventArg.GetType() == typeof(RequestEventArgs)) { RequestEventArgs request = (RequestEventArgs)eventArg; if (request.Request == RequestCode.BeginShutdown) { OnServiceStateChanged(m_ServiceState, ServiceStates.Stopping); m_ServiceState = ServiceStates.Stopping; // Purge all write queues now. // If all things are completed, then shutdown completely now. // Otherwise, we will have to check after each periodic update to see when all work // has been completed. bool isReadyToStop = true; if (isReadyToStop) { m_ServiceState = ServiceStates.Stopped; OnServiceStateChanged(ServiceStates.Stopping, ServiceStates.Stopped); base.Stop(); } } } } }//HubEventHandler()