public ParsedRequest(bool forCache) { Select = SelectStatementData.Create(); BaseDataset = BaseDatasetData.Create(); Modify = InsertUpdateDeleteStatementData.Create(); BulkInput = BulkInputData.Create(); Params = ParametersData.Create(); SpecialCommand = SpecialCommandData.Create(); Bulk = forCache ? null : new BufferedReaderStream(84980); }
/// <summary> /// RequestProcessingManager's (RPM) <see cref="WriteTo"/> works in parallel with <see cref="DataEngine.ProducerThreadMethod"/>. /// RPM supplies empty buffers to be filled with data into <see cref="RequestExecutionContext.BuffersRing"/> and consumes them on the other end. /// The data ring has very limited number of buffers. /// RPM is limited by network throughput and Producer's speed. /// Producer is limited by underlying storage driver, local processing speed and RPM's consumption of complete buffers. /// The difference between the two: RPM <see cref="WriteTo"/> is scheduled for execution by service infrastructure (WCF), /// whereas <see cref="DataEngine.ProducerThreadMethod"/> is scheduled by RPM itself, when it invokes <see cref="IDataEngine.BeginExecution"/>. /// </summary> public void WriteTo(Stream output) { // We will not report to client any unhandled errors from producer thread. // As of our local errors, we can only send them to client BEFORE the first block of data is streamed out. var canReportLocalErrors = true; try { using (var binaryWriter = new BinaryWriter(output, Encoding.UTF8, true)) { // rotate through the buffers, flush them to output until producer stops var cancellation = m_executionContext.CancellationTokenSource.Token; var buffersRing = m_executionContext.BuffersRing; var lastCompletedTask = buffersRing.TakeCompletedTask(cancellation); while (lastCompletedTask != null) { // no more reporting of local errors after first block has been generated // note that this block may itself contain error information, but this is unrelated canReportLocalErrors = false; var stream = lastCompletedTask.Stream; var toWrite = checked ((int)stream.Length); if (toWrite == 0) { break; } // write block var buffer = stream.GetBuffer(); BufferedReaderStream.WriteBlock(binaryWriter, toWrite, buffer); ReportStats(toWrite, lastCompletedTask.RowsOutput); // this task might have produced error information instead of real data // or it might have finished producing rows // in both cases, break further processing if (lastCompletedTask.IsFailed || lastCompletedTask.RowsOutput == 0) { break; } // return buffer to the ring buffersRing.AddTaskForProcessing(lastCompletedTask, cancellation); // take next one lastCompletedTask = buffersRing.TakeCompletedTask(cancellation); } BufferedReaderStream.WriteStreamEndMarker(binaryWriter); // no more data in the input sequence, or just have to stop producing buffersRing.CompleteAddingTasksForProcessing(); } } catch (Exception e) { m_executionContext.Cancel(e); if (canReportLocalErrors) { using (var errorWriter = new PqlErrorDataWriter(1, m_executionContext.LastError, true)) { errorWriter.WriteTo(output); } } if (!(e is OperationCanceledException)) { throw; } } }