/// <summary> /// Seek an async handler on the min number of requests queued in memory and its associated socket connection /// </summary> /// <returns>An async handler if found; and null or nothing if no connection is found</returns> public virtual THandler Seek() { THandler h = null; lock (m_cs) { foreach (CClientSocket cs in m_dicSocketHandler.Keys) { if (cs.ConnectionState < tagConnectionState.csSwitched) { continue; } if (h == null) { h = m_dicSocketHandler[cs]; } else { IClientQueue cq = h.Socket.ClientQueue; ulong cs_coriq = cq.Available ? cq.MessageCount : cs.CountOfRequestsInQueue; cq = h.Socket.ClientQueue; ulong h_coriq = cq.Available ? cq.MessageCount : h.Socket.CountOfRequestsInQueue; if (cs_coriq < h_coriq) { h = m_dicSocketHandler[cs]; } else if (cs_coriq == h_coriq && cs.BytesSent < h.Socket.BytesSent) { h = m_dicSocketHandler[cs]; } } } } return(h); }
/// <summary> /// Seek an async handler on the min number of requests queued and its associated socket connection /// </summary> /// <returns>An async handler if found; and null or nothing if no proper queue is available</returns> public virtual THandler SeekByQueue() { THandler h = null; lock (m_cs) { foreach (CClientSocket cs in m_dicSocketHandler.Keys) { IClientQueue cq = cs.ClientQueue; if (!cq.Available || cq.JobSize > 0 /*queue is in transaction at this time*/) { continue; } if (h == null) { h = m_dicSocketHandler[cs]; } else if ((cq.MessageCount < h.Socket.ClientQueue.MessageCount) || (cs.Connected && !h.Socket.Connected)) { h = m_dicSocketHandler[cs]; } } } return(h); }
/// <summary> /// End enqueuing messages with transaction style. Currently, total size of queued messages must be less than 4 G bytes /// </summary> /// <param name="rollback">true for rollback, and false for committing</param> /// <param name="qt">A callback for tracking returning error code, which can be one of QUEUE_OK, QUEUE_TRANS_NOT_STARTED_YET, and so on</param> /// <param name="discarded">a callback for tracking cancel or socket closed event</param> /// <returns>true for sending the request successfully, and false for failure</returns> public virtual bool EndQueueTrans(bool rollback, DQueueTrans qt, DDiscarded discarded) { bool ok = SendRequest(idEndTrans, rollback, (ar) => { if (qt != null) { int errCode; ar.UQueue.Load(out errCode); qt((CAsyncQueue)ar.AsyncServiceHandler, errCode); } else { ar.UQueue.SetSize(0); } }, discarded, (DOnExceptionFromServer)null); IClientQueue cq = AttachedClientSocket.ClientQueue; if (cq.Available) { if (rollback) { cq.AbortJob(); } else { cq.EndJob(); } } return(ok); }
/// <summary> /// Start enqueuing messages with transaction style. Currently, total size of queued messages must be less than 4 G bytes /// </summary> /// <param name="key">An ASCII string for identifying a queue at server side</param> /// <param name="qt">A callback for tracking returning error code, which can be one of QUEUE_OK, QUEUE_TRANS_ALREADY_STARTED, and so on</param> /// <returns>true for sending the request successfully, and false for failure</returns> public bool StartQueueTrans(byte[] key, DQueueTrans qt) { IClientQueue cq = AttachedClientSocket.ClientQueue; if (cq.Available) { cq.StartJob(); } using (CScopeUQueue sq = new CScopeUQueue()) { sq.UQueue.Save(key); return(SendRequest(idStartTrans, sq, (ar) => { if (qt != null) { int errCode; ar.UQueue.Load(out errCode); qt((CAsyncQueue)ar.AsyncServiceHandler, errCode); } else { ar.UQueue.SetSize(0); } })); } }
/// <summary> /// Seek an async handler on the min number of requests queued and its associated socket connection /// </summary> /// <returns>An async handler if found; and null or nothing if no proper queue is available</returns> public virtual THandler SeekByQueue() { THandler h = null; lock (m_cs) { bool automerge = (ClientCoreLoader.GetQueueAutoMergeByPool(m_nPoolId) > 0); foreach (CClientSocket cs in m_dicSocketHandler.Keys) { if (automerge && cs.ConnectionState < tagConnectionState.csSwitched) { continue; } IClientQueue cq = cs.ClientQueue; if (!cq.Available || cq.JobSize > 0 /*queue is in transaction at this time*/) { continue; } if (h == null) { h = m_dicSocketHandler[cs]; } else if ((cq.MessageCount < h.AttachedClientSocket.ClientQueue.MessageCount) || (cs.Connected && !h.AttachedClientSocket.Connected)) { h = m_dicSocketHandler[cs]; } } } return(h); }
/// <summary> /// Lock an asynchronous handler from socket pool. You must call this method with UnlockByMyAlgorithm in pair /// </summary> /// <param name="timeout">The max time for locking a handler in ms</param> /// <returns>A SQL handler from socket pool</returns> public CSql LockByMyAlgorithm(int timeout) { CSql sql = null; System.Threading.Monitor.Enter(m_cs); while (timeout >= 0) { CClientSocket ret = null; foreach (CClientSocket cs in m_dicSocketHandler.Keys) { IClientQueue cq = cs.ClientQueue; if (!cq.Available || cq.JobSize > 0 /*queue is in transaction at this time*/) { continue; //A null handler may return if local message queue is in transaction } if (ret == null) { ret = cs; } else if (cs.Connected) { if (!ret.Connected) { ret = cs; } else if (cq.MessageCount < ret.ClientQueue.MessageCount) { ret = cs; } } else if (!ret.Connected && cq.MessageCount < ret.ClientQueue.MessageCount) { ret = cs; } } if (ret != null) { sql = m_dicSocketHandler[ret]; m_dicSocketHandler.Remove(ret); } if (sql != null) { break; } System.DateTime dtNow = System.DateTime.Now; bool ok = System.Threading.Monitor.Wait(m_cs, timeout); int ts = (int)(System.DateTime.Now - dtNow).TotalMilliseconds; if (!ok || timeout <= ts) { break; } timeout -= ts; } System.Threading.Monitor.Exit(m_cs); return(sql); //A null handler may return in case time-out }
public bool AbortJob() { IClientQueue src = SourceQueue; if (src == null || !src.Available) { return(false); } return(src.AbortJob()); }
/// <summary> /// Make a replication. An invalid operation exception will be thrown if not replicable. /// </summary> /// <returns>True for success; and false for failure</returns> public bool DoReplication() { if (m_mapQueueConn.Count == 1) { throw new InvalidOperationException("No replication is allowed because the number of target message queues less than two"); } IClientQueue src = SourceQueue; if (src == null) { return(false); } return(src.AppendTo(TargetQueues)); }
public bool EndJob() { IClientQueue src = SourceQueue; if (src == null || !src.Available) { return(false); } bool ok = src.EndJob(); if (ok && Replicable) { ok = src.AppendTo(TargetQueues); } return(ok); }
virtual public bool Send(ushort reqId, byte[] data, uint len) { CAsyncServiceHandler.DAsyncResultHandler ash = null; THandler src = SourceHandler; if (src == null) { return(false); } IClientQueue cq = src.AttachedClientSocket.ClientQueue; if (!cq.Available) { return(false); } bool ok = src.SendRequest(reqId, data, len, ash); if (Replicable && cq.JobSize == 0) { ok = cq.AppendTo(TargetQueues); } return(ok); }
public bool EnsureAppending(IClientQueue clientQueue) { if (clientQueue == null) return true; IntPtr[] queueHandles = { clientQueue.Handle }; return EnsureAppending(queueHandles); }
/// <summary> /// Send affected record set from a trigger for table update, delete or insert onto one or more remote SocketPro servers with auto replication if required. /// </summary> /// <param name="tableName">A valid table name</param> /// <param name="param">An extra info data. For example, a trigger name</param> /// <param name="batchSize">The size of a set of records in byte. It defaults to CAsyncAdoSerializationHelper.DEFAULT_BATCH_SIZE</param> /// <returns>True for success; and false for failure</returns> public virtual bool SendDmlTrigger(string tableName, object param, uint batchSize) { bool jobing = false; bool ok = true; if (tableName == null) { throw new ArgumentNullException("A valid table name required"); } if (tableName.Length == 0) { throw new ArgumentException("A valid table name required"); } IClientQueue srcQueue = SourceQueue; if (srcQueue == null || !srcQueue.Available) { throw new InvalidOperationException("No queue available for persisting data"); } TriggerAction ta = SqlContext.TriggerContext.TriggerAction; using (SqlConnection conn = new SqlConnection("context connection=true")) { CAsyncServiceHandler.DAsyncResultHandler arh = null; SqlDataReader dr = null; try { conn.Open(); lock (m_csSs) { jobing = (srcQueue.JobSize != 0); THandler h = SourceHandler; try { if (!jobing) { ok = StartJob(); } switch (ta) { case TriggerAction.Update: case TriggerAction.Delete: case TriggerAction.Insert: ok = h.SendRequest(CAsyncAdoSerializationHelper.idDmlTriggerMessage, (int)ta, Utilities.GetObjectFullName(conn, tableName, "U"), param, arh); break; default: throw new InvalidOperationException("SendDmlTrigger for table update, insert and delete events only"); } if (ta == TriggerAction.Update || ta == TriggerAction.Delete) { SqlCommand cmd = new SqlCommand("select * from deleted", conn); dr = cmd.ExecuteReader(); ok = h.Send(dr, batchSize); dr.Close(); } if (ta == TriggerAction.Update || ta == TriggerAction.Insert) { SqlCommand cmd = new SqlCommand("select * from inserted", conn); dr = cmd.ExecuteReader(); ok = h.Send(dr, batchSize); dr.Close(); } if (!jobing) { ok = EndJob(); } ok = true; } catch { if (dr != null) { dr.Close(); } if (!jobing) { ok = AbortJob(); } ok = false; } } } finally { conn.Close(); } } return(ok); }
/// <summary> /// Send a record set from a given query statement onto one or more remote SocketPro servers with auto replication if required /// </summary> /// <param name="sqlQuery">A statement creating a set of records</param> /// <param name="recordsetName">An string name for this record set</param> /// <param name="batchSize">The size of a set of records in byte. It defaults to CAsyncAdoSerializationHelper.DEFAULT_BATCH_SIZE</param> public virtual bool Send(string sqlQuery, string recordsetName, uint batchSize) { bool ok = false; bool jobing = false; if (sqlQuery == null || sqlQuery.Length == 0) { throw new ArgumentException("A valid sql select query required"); } IClientQueue srcQueue = SourceQueue; if (srcQueue == null || !srcQueue.Available) { throw new InvalidOperationException("No queue available for persisting data"); } using (SqlConnection conn = new SqlConnection("context connection=true")) { CAsyncServiceHandler.DAsyncResultHandler arh = null; SqlDataReader dr = null; try { conn.Open(); lock (m_csSs) { jobing = (srcQueue.JobSize != 0); THandler h = SourceHandler; try { if (!jobing) { ok = StartJob(); } ok = h.SendRequest(CAsyncAdoSerializationHelper.idRecordsetName, recordsetName, arh); SqlCommand cmd = new SqlCommand(sqlQuery, conn); dr = cmd.ExecuteReader(); do { ok = h.Send(dr, batchSize); } while (dr.NextResult()); dr.Close(); if (!jobing) { ok = EndJob(); } ok = true; } catch { if (dr != null) { dr.Close(); } if (!jobing) { ok = AbortJob(); } ok = false; } } } finally { conn.Close(); } } return(ok); }
public bool AppendTo(IClientQueue[] clientQueues) { if (clientQueues == null || clientQueues.Length == 0) return true; List<IntPtr> qs = new List<IntPtr>(); foreach (IClientQueue cq in clientQueues) { qs.Add(cq.Handle); } return AppendTo(qs.ToArray()); }
private bool Transfer() { int index = 0; DAsyncResultHandler rh = null; DOnExceptionFromServer se = null; CClientSocket cs = AttachedClientSocket; if (!cs.Sendable) { return(false); } uint sent_buffer_size = cs.BytesInSendingBuffer; if (sent_buffer_size > 3 * STREAM_CHUNK_SIZE) { return(true); } while (index < m_vContext.Count) { CContext context = m_vContext[index]; if (context.Sent) { ++index; continue; } if (context.Uploading && context.Tried && context.File == null) { if (index == 0) { if (context.Upload != null) { context.Upload(this, CANNOT_OPEN_LOCAL_FILE_FOR_READING, context.ErrMsg); } m_vContext.RemoveFromFront(); } else { ++index; } continue; } if (context.Uploading) { if (!context.Tried) { context.Tried = true; try { FileShare fs = FileShare.None; if ((context.Flags & FILE_OPEN_SHARE_READ) == FILE_OPEN_SHARE_READ) { fs = FileShare.Read; } context.File = new FileStream(context.LocalFile, FileMode.Open, FileAccess.Read, fs); context.FileSize = context.File.Length; IClientQueue cq = AttachedClientSocket.ClientQueue; if (cq.Available) { if (!cq.StartJob()) { context.File.Close(); context.File = null; throw new Exception("Cannot start queue job"); } } if (!SendRequest(idUpload, context.FilePath, context.Flags, context.FileSize, rh, context.Discarded, se)) { return(false); } } catch (Exception err) { context.ErrMsg = err.Message; } finally { } } if (context.File == null) { if (index == 0) { if (context.Upload != null) { context.Upload(this, CANNOT_OPEN_LOCAL_FILE_FOR_READING, context.ErrMsg); } m_vContext.RemoveFromFront(); } else { ++index; } continue; } else { using (CScopeUQueue sb = new CScopeUQueue()) { if (sb.UQueue.MaxBufferSize < STREAM_CHUNK_SIZE) { sb.UQueue.Realloc(STREAM_CHUNK_SIZE); } byte[] buffer = sb.UQueue.IntenalBuffer; int ret = context.File.Read(buffer, 0, (int)STREAM_CHUNK_SIZE); while (ret > 0) { if (!SendRequest(idUploading, buffer, (uint)ret, rh, context.Discarded, se)) { return(false); } sent_buffer_size = cs.BytesInSendingBuffer; if (ret < (int)STREAM_CHUNK_SIZE) { break; } if (sent_buffer_size >= 5 * STREAM_CHUNK_SIZE) { break; } ret = context.File.Read(buffer, 0, (int)STREAM_CHUNK_SIZE); } if (ret < (int)STREAM_CHUNK_SIZE) { context.Sent = true; if (!SendRequest(idUploadCompleted, rh, context.Discarded, se)) { return(false); } IClientQueue cq = AttachedClientSocket.ClientQueue; if (cq.Available) { cq.EndJob(); } } if (sent_buffer_size >= 4 * STREAM_CHUNK_SIZE) { break; } } } } else { if (!SendRequest(idDownload, context.FilePath, context.Flags, rh, context.Discarded, se)) { return(false); } context.Sent = true; context.Tried = true; sent_buffer_size = cs.BytesInSendingBuffer; if (sent_buffer_size > 3 * STREAM_CHUNK_SIZE) { break; } } ++index; } return(true); }
private void OnSPEvent(uint poolId, tagSocketPoolEvent spe, IntPtr h) { THandler handler = MapToHandler(h); switch (spe) { case tagSocketPoolEvent.speTimer: if (CScopeUQueue.MemoryConsumed / 1024 > CScopeUQueue.SHARED_BUFFER_CLEAN_SIZE) { CScopeUQueue.DestroyUQueuePool(); } break; case tagSocketPoolEvent.speStarted: lock (m_cs) { m_nPoolId = poolId; } break; case tagSocketPoolEvent.speShutdown: lock (m_cs) { m_dicSocketHandler.Clear(); } break; case tagSocketPoolEvent.speUSocketCreated: { CClientSocket cs = new CClientSocket(); cs.Set(h); ClientCoreLoader.SetRecvTimeout(h, m_recvTimeout); ClientCoreLoader.SetConnTimeout(h, m_connTimeout); ClientCoreLoader.SetAutoConn(h, (byte)(m_autoConn ? 1 : 0)); handler = new THandler(); if (handler.SvsID == 0) { handler.m_nServiceId = m_ServiceId; } if (handler.SvsID <= SocketProAdapter.BaseServiceID.sidStartup) { throw new InvalidOperationException("Service id must be larger than SocketProAdapter.BaseServiceID.sidStartup"); } handler.Attach(cs); lock (m_cs) { m_dicSocketHandler[cs] = handler; } } break; case tagSocketPoolEvent.speUSocketKilled: if (handler != null) { lock (m_cs) { m_dicSocketHandler.Remove(handler.AttachedClientSocket); } } break; case tagSocketPoolEvent.speConnecting: break; case tagSocketPoolEvent.speConnected: if (ClientCoreLoader.IsOpened(h) != 0) { CClientSocket cs = handler.AttachedClientSocket; if (DoSslServerAuthentication != null && cs.EncryptionMethod == tagEncryptionMethod.TLSv1 && !DoSslServerAuthentication.Invoke(this, cs)) { return; //don't set password or call SwitchTo in case failure of ssl server authentication on certificate from server } ClientCoreLoader.SetSockOpt(h, tagSocketOption.soRcvBuf, 116800, tagSocketLevel.slSocket); ClientCoreLoader.SetSockOpt(h, tagSocketOption.soSndBuf, 116800, tagSocketLevel.slSocket); ClientCoreLoader.SetSockOpt(h, tagSocketOption.soTcpNoDelay, 1, tagSocketLevel.slTcp); ClientCoreLoader.SetPassword(h, cs.ConnectionContext.GetPassword()); bool ok = ClientCoreLoader.StartBatching(h) != 0; ok = ClientCoreLoader.SwitchTo(h, handler.SvsID) != 0; ok = ClientCoreLoader.TurnOnZipAtSvr(h, (byte)(cs.ConnectionContext.Zip ? 1 : 0)) != 0; ok = ClientCoreLoader.SetSockOptAtSvr(h, tagSocketOption.soRcvBuf, 116800, tagSocketLevel.slSocket) != 0; ok = ClientCoreLoader.SetSockOptAtSvr(h, tagSocketOption.soSndBuf, 116800, tagSocketLevel.slSocket) != 0; ok = ClientCoreLoader.SetSockOptAtSvr(h, tagSocketOption.soTcpNoDelay, 1, tagSocketLevel.slTcp) != 0; ok = (ClientCoreLoader.CommitBatching(h, (byte)0) != 0); } break; case tagSocketPoolEvent.speQueueMergedFrom: m_pHFrom = MapToHandler(h); #if DEBUG IClientQueue cq = m_pHFrom.AttachedClientSocket.ClientQueue; uint remaining = (uint)m_pHFrom.RequestsQueued; if (cq.MessageCount != remaining) { Console.WriteLine("From: Messages = {0}, remaining requests = {1}", cq.MessageCount, remaining); } #endif break; case tagSocketPoolEvent.speQueueMergedTo: { THandler to = MapToHandler(h); m_pHFrom.AppendTo(to); m_pHFrom = null; } break; default: break; } if (SocketPoolEvent != null) { SocketPoolEvent.Invoke(this, spe, handler); } OnSocketPoolEvent(spe, handler); if (spe == tagSocketPoolEvent.speConnected && ClientCoreLoader.IsOpened(h) != 0) { SetQueue(handler.AttachedClientSocket); } }
public bool AppendTo(IClientQueue clientQueue) { if (clientQueue == null) return true; IntPtr[] queueHandles = { clientQueue.Handle }; return AppendTo(queueHandles); }