private void VerifyTimeout(int writeTimeout) { using (var com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName)) using (var com2 = new SerialPort(TCSupport.LocalMachineSerialInfo.SecondAvailablePortName)) { var asyncRead = new AsyncWrite(com1); var asyncEndWrite = new Task(asyncRead.EndWrite); var asyncCallbackCalled = false; com1.Open(); com2.Open(); com1.Handshake = Handshake.RequestToSend; com1.WriteTimeout = writeTimeout; IAsyncResult writeAsyncResult = com1.BaseStream.BeginWrite(new byte[8], 0, 8, ar => asyncCallbackCalled = true, null); asyncRead.WriteAsyncResult = writeAsyncResult; Thread.Sleep(100 > com1.WriteTimeout ? 2 * com1.WriteTimeout : 200); // Sleep for 200ms or 2 times the WriteTimeout if (writeAsyncResult.IsCompleted) { // Verify the IAsyncResult has not completed Fail("Err_565088aueiud!!!: Expected read to not have completed"); } asyncEndWrite.Start(); TCSupport.WaitForTaskToStart(asyncEndWrite); Thread.Sleep(100 < com1.WriteTimeout ? 2 * com1.WriteTimeout : 200); // Sleep for 200ms or 2 times the WriteTimeout if (asyncEndWrite.IsCompleted) { // Verify EndRead is blocking and is still alive Fail("Err_4085858aiehe!!!: Expected read to not have completed"); } if (asyncCallbackCalled) { Fail("Err_750551aiuehd!!!: Expected AsyncCallback not to be called"); } com2.RtsEnable = true; TCSupport.WaitForTaskCompletion(asyncEndWrite); var waitTime = 0; while (!asyncCallbackCalled && waitTime < 5000) { Thread.Sleep(50); waitTime += 50; } if (!asyncCallbackCalled) { Fail( "Err_21208aheide!!!: Expected AsyncCallback to be called after some data was written to the port"); } } }
public AsyncWrite(AsyncWrite other) : base(other) { this.writePolicy = other.writePolicy; this.listener = other.listener; this.key = other.key; this.bins = other.bins; this.operation = other.operation; }
/// <summary> /// May return either a physical file name or a MemoryStream with the data. /// Faster than GetCachedFile, as writes are (usually) asynchronous. If the write queue is full, the write is forced to be synchronous again. /// Identical to GetCachedFile() when asynchronous=false /// </summary> /// <param name="keyBasis"></param> /// <param name="extension"></param> /// <param name="writeCallback"></param> /// <param name="timeoutMs"></param> /// <returns></returns> public CacheResult GetCachedFile(string keyBasis, string extension, ResizeImageDelegate writeCallback, int timeoutMs, bool asynchronous) { Stopwatch sw = null; if (lp.Logger != null) { sw = new Stopwatch(); sw.Start(); } // Path to the file in the blob container string path = new UrlHasher().Hash(keyBasis) + '.' + extension; CacheResult result = new CacheResult(CacheQueryResult.Hit, path); bool asyncFailed = false; //2013-apr-25: What happens if the file is still being written to blob storage - it's present but not complete? To handle that, we use mayBeLocked. bool mayBeLocked = Locks.MayBeLocked(path.ToUpperInvariant()); // On the first check, verify the file exists by connecting to the blob directly if (!asynchronous) { //May throw an IOException if the file cannot be opened, and is locked by an external processes for longer than timeoutMs. //This method may take longer than timeoutMs under absolute worst conditions. if (!TryWriteFile(result, path, writeCallback, timeoutMs, !mayBeLocked)) { //On failure result.Result = CacheQueryResult.Failed; } } else if (!Index.PathExistInIndex(path) || mayBeLocked) { //Looks like a miss. Let's enter a lock for the creation of the file. This is a different locking system than for writing to the file - far less contention, as it doesn't include the //This prevents two identical requests from duplicating efforts. Different requests don't lock. //Lock execution using relativePath as the sync basis. Ignore casing differences. This prevents duplicate entries in the write queue and wasted CPU/RAM usage. if (!QueueLocks.TryExecute(path.ToUpperInvariant(), timeoutMs, delegate() { //Now, if the item we seek is in the queue, we have a memcached hit. If not, we should check the index. It's possible the item has been written to disk already. //If both are a miss, we should see if there is enough room in the write queue. If not, switch to in-thread writing. AsyncWrite t = CurrentWrites.Get(path); if (t != null) { result.Data = t.GetReadonlyStream(); } //On the second check, use cached data for speed. The cached data should be updated if another thread updated a file (but not if another process did). //When t == null, and we're inside QueueLocks, all work on the file must be finished, so we have no need to consult mayBeLocked. if (t == null && !Index.PathExistInIndex(path)) { result.Result = CacheQueryResult.Miss; //Still a miss, we even rechecked the filesystem. Write to memory. MemoryStream ms = new MemoryStream(4096); //4K initial capacity is minimal, but this array will get copied around alot, better to underestimate. //Read, resize, process, and encode the image. Lots of exceptions thrown here. writeCallback(ms); ms.Position = 0; AsyncWrite w = new AsyncWrite(CurrentWrites, ms, path); if (CurrentWrites.Queue(w, delegate(AsyncWrite job) { try { Stopwatch swio = new Stopwatch(); swio.Start(); //TODO: perhaps a different timeout? if (!TryWriteFile(null, job.Path, delegate(Stream s) { ((MemoryStream)job.GetReadonlyStream()).WriteTo(s); }, timeoutMs, true)) { swio.Stop(); //We failed to lock the file. if (lp.Logger != null) { lp.Logger.Warn("Failed to flush async write, timeout exceeded after {1}ms - {0}", result.Path, swio.ElapsedMilliseconds); } } else { swio.Stop(); if (lp.Logger != null) { lp.Logger.Trace("{0}ms: Async write started {1}ms after enqueue for {2}", swio.ElapsedMilliseconds.ToString().PadLeft(4), DateTime.UtcNow.Subtract(w.JobCreatedAt).Subtract(swio.Elapsed).TotalMilliseconds, result.Path); } } } catch (Exception ex) { if (lp.Logger != null) { lp.Logger.Error("Failed to flush async write, {0} {1}\n{2}", ex.ToString(), result.Path, ex.StackTrace); } } finally { CurrentWrites.Remove(job); //Remove from the queue, it's done or failed. } })) { //We queued it! Send back a read-only memory stream result.Data = w.GetReadonlyStream(); } else { asyncFailed = false; //We failed to queue it - either the ThreadPool was exhausted or we exceeded the MB limit for the write queue. //Write the MemoryStream to disk using the normal method. //This is nested inside a queuelock because if we failed here, the next one will also. Better to force it to wait until the file is written to blob storage. if (!TryWriteFile(result, path, delegate(Stream s) { ms.WriteTo(s); }, timeoutMs, false)) { if (lp.Logger != null) { lp.Logger.Warn("Failed to queue async write, also failed to lock for sync writing: {0}", result.Path); } } } } })) { //On failure result.Result = CacheQueryResult.Failed; } } if (lp.Logger != null) { sw.Stop(); lp.Logger.Trace("{0}ms: {3}{1} for {2}, Key: {4}", sw.ElapsedMilliseconds.ToString(NumberFormatInfo.InvariantInfo).PadLeft(4), result.Result.ToString(), result.Path, asynchronous ? (asyncFailed ? "Fallback to sync " : "Async ") : "", keyBasis); } //Fire event if (CacheResultReturned != null) { CacheResultReturned(this, result); } return(result); }
/* * @ 以异步方式启动写入日志 * */ private void WriteLocal(string text, LogType type, Exception ex) { AsyncWrite asyncWrite = new AsyncWrite(Write); IAsyncResult result = asyncWrite.BeginInvoke(text, type, ex, logRecordType, null, null); }
private bool VerifyTimeout(int writeTimeout) { SerialPort com1 = new SerialPort(TCSupport.LocalMachineSerialInfo.FirstAvailablePortName); SerialPort com2 = new SerialPort(TCSupport.LocalMachineSerialInfo.SecondAvailablePortName); bool retValue = true; System.IAsyncResult writeAsyncResult; AsyncWrite asyncRead = new AsyncWrite(com1); System.Threading.Thread asyncEndWrite = new System.Threading.Thread(new System.Threading.ThreadStart(asyncRead.EndWrite)); int waitTime; bool asyncCallbackCalled = false; com1.Open(); com2.Open(); com1.Handshake = Handshake.RequestToSend; com1.WriteTimeout = writeTimeout; writeAsyncResult = com1.BaseStream.BeginWrite(new byte[8], 0, 8, delegate(IAsyncResult ar) { asyncCallbackCalled = true; }, null); asyncRead.WriteAsyncResult = writeAsyncResult; System.Threading.Thread.Sleep(100 > com1.WriteTimeout ? 2 * com1.WriteTimeout : 200); //Sleep for 200ms or 2 times the WriteTimeout if (writeAsyncResult.IsCompleted) {//Verify the IAsyncResult has not completed Console.WriteLine("Err_565088aueiud!!!: Expected read to not have completed"); retValue = false; } asyncEndWrite.Start(); waitTime = 0; while (asyncEndWrite.ThreadState == System.Threading.ThreadState.Unstarted && waitTime < MAX_WAIT_THREAD) {//Wait for the thread to start System.Threading.Thread.Sleep(50); waitTime += 50; } if (MAX_WAIT_THREAD <= waitTime) { Console.WriteLine("Err_018158ajied!!!: Expected EndRead to have returned"); retValue = false; } System.Threading.Thread.Sleep(100 < com1.WriteTimeout ? 2 * com1.WriteTimeout : 200); //Sleep for 200ms or 2 times the WriteTimeout if (!asyncEndWrite.IsAlive) {//Verify EndRead is blocking and is still alive Console.WriteLine("Err_4085858aiehe!!!: Expected read to not have completed"); retValue = false; } if (asyncCallbackCalled) { Console.WriteLine("Err_750551aiuehd!!!: Expected AsyncCallback not to be called"); retValue = false; } com2.RtsEnable = true; waitTime = 0; while (asyncEndWrite.IsAlive && waitTime < MAX_WAIT_THREAD) { System.Threading.Thread.Sleep(50); waitTime += 50; } if (MAX_WAIT_THREAD <= waitTime) { Console.WriteLine("Err_018158ajied!!!: Expected EndRead to have returned"); retValue = false; } waitTime = 0; while (!asyncCallbackCalled && waitTime < 5000) { System.Threading.Thread.Sleep(50); waitTime += 50; } if (!asyncCallbackCalled) { Console.WriteLine("Err_21208aheide!!!: Expected AsyncCallback to be called after some data was written to the port"); retValue = false; } if (com1.IsOpen) { com1.Close(); } if (com2.IsOpen) { com2.Close(); } return(retValue); }