Exemplo n.º 1
0
        /// <summary>
        /// Writes the buffer to SQL and empties it.
        /// </summary>
        private void WriteData()
        {
            lock (this)
            {
                // This and the lock are to circumvent a small multithreading dillema
                if (this.Available)
                {
                    Trace.WriteLine(String.Format(CultureInfo.InvariantCulture,
                                                  "BufferRecorder::WriteData called when Available at time {0}.  Returning.",
                                                  DateTime.Now.Ticks));
                    return;
                }

                // Going to try a spin-wait just to see if we can resolve this multithreading problem
                while (this.writing)
                {
                    Thread.Sleep(10);
                }

                writing = true;
                bool overflowed;

                do
                {
                    overflowed = false;

                    try
                    {
                        // Don't try to write an empty buffer
                        if (currentIndex > 0)
                        {
#if TIMING
                            long startTimer = DateTime.Now.Ticks;
#endif
                            // Try to detect and fix overflow before it happens to avoid the exception and hopefully improve performance.
                            if (DBHelper.WouldOverflowStream(this.streamID, this.indices[this.currentIndex - 1].end))
                            {
                                this.Overflowed(this, EventArgs.Empty);
                            }

                            // TODO: Find out why this gets called twice on one data set OR find a workaround.
                            Trace.WriteLine(String.Format(CultureInfo.InvariantCulture,
                                                          "BufferRecorder::WriteData doing SBAI on buffer {0}, stream {1} at {2}",
                                                          number, streamID, DateTime.Now.Ticks));
                            DBHelper.SaveBufferAndIndices(
                                this.streamID,
                                this.indices,
                                this.currentIndex,
                                buffer);

#if TIMING
                            long takenTime = DateTime.Now.Ticks - startTimer;
                            Trace.WriteLine(string.Format(CultureInfo.InvariantCulture, "TIMING: SBAI took {0} ms",
                                                          (takenTime / Constants.TicksPerMs)));
#endif
                        }
                    }
                    catch (SqlException ex)
                    {
                        // Catch the overflow case, where we have more data than the 'int' type holds
                        if (ex.Message.ToLower(CultureInfo.InvariantCulture).IndexOf("overflow") >= 0)
                        {
                            overflowed = true; // by setting this, we directly try to write the data again
                            this.Overflowed(this, EventArgs.Empty);
                        }

                        // Two exceptions are seen here:
                        //   Timeouts in SQL due to taking a *really* bad performance beating
                        //   OR Constraint violation in Frame table due to unusual multithreading problem not yet solved (mentioned above)
                        // Dont do anything, b/c failed DB ops are already event-logged.  Just move on & hope that the stream is playable.
                    }
                    catch (InvalidOperationException ex)
                    {
                        // In the worst of performance cases, we run out of pooled connections and get this exception
                        eventLog.WriteEntry(string.Format(CultureInfo.CurrentCulture, Strings.DatabaseOperationFailedError,
                                                          ex.ToString()), EventLogEntryType.Error, ArchiveServiceEventLog.ID.DBOpFailed);

                        // Again, ignore & move on, dropping the frames.
                    }
                } // In the specific case where we've overflowed, try again immediately (to hopefully preempt other buffers from going out-of-order)
                while (overflowed);

                writing     = false;
                isAvailable = true;

                bufferIndex  = 0;
                currentIndex = 0;

                Trace.WriteLine("BufferRecorder::WriteData completed.");
            }
        }