예제 #1
0
            protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
            {
                var old     = CurrentOperationContext.Headers.Value;
                var oldUser = CurrentOperationContext.User.Value;

                try
                {
                    CurrentOperationContext.User.Value    = user;
                    CurrentOperationContext.Headers.Value = headers;
                    var bufferSize = queryOp.Header.TotalResults > 1024 ? 1024 * 64 : 1024 * 8;
                    using (var bufferedStream = new BufferedStream(stream, bufferSize))
                        using (queryOp)
                            using (accessor)
                                using (_timeout)
                                    using (var writer = GetOutputWriter(req, bufferedStream))
                                        // we may be sending a LOT of documents to the user, and most
                                        // of them aren't going to be relevant for other ops, so we are going to skip
                                        // the cache for that, to avoid filling it up very quickly
                                        using (DocumentCacher.SkipSetAndGetDocumentsInDocumentCache())
                                        {
                                            outputContentTypeSetter(writer.ContentType);

                                            writer.WriteHeader();
                                            try
                                            {
                                                queryOp.Execute(o =>
                                                {
                                                    _timeout.Delay();
                                                    if (modifyDocument != null)
                                                    {
                                                        o = modifyDocument(o);
                                                    }
                                                    writer.Write(o);
                                                });
                                            }
                                            catch (Exception e)
                                            {
                                                writer.WriteError(e);
                                            }
                                        }
                    return(Task.FromResult(true));
                }
                finally
                {
                    CurrentOperationContext.Headers.Value = old;
                    CurrentOperationContext.User.Value    = oldUser;
                }
            }
예제 #2
0
        private void StreamToClient(long id, SubscriptionActions subscriptions, Stream stream)
        {
            var sentDocuments = false;

            var bufferStream = new BufferedStream(stream, 1024 * 64);

            using (var writer = new JsonTextWriter(new StreamWriter(bufferStream)))
            {
                var options = subscriptions.GetBatchOptions(id);

                writer.WriteStartObject();
                writer.WritePropertyName("Results");
                writer.WriteStartArray();

                using (var cts = new CancellationTokenSource())
                    using (var timeout = cts.TimeoutAfter(DatabasesLandlord.SystemConfiguration.DatabaseOperationTimeout))
                    {
                        Etag lastProcessedDocEtag = null;

                        var batchSize          = 0;
                        var batchDocCount      = 0;
                        var processedDocuments = 0;
                        var hasMoreDocs        = false;
                        var config             = subscriptions.GetSubscriptionConfig(id);
                        var startEtag          = config.AckEtag;
                        var criteria           = config.Criteria;

                        bool isPrefixCriteria = !string.IsNullOrWhiteSpace(criteria.KeyStartsWith);

                        Func <JsonDocument, bool> addDocument = doc =>
                        {
                            timeout.Delay();
                            if (doc == null)
                            {
                                // we only have this heartbeat when the streaming has gone on for a long time
                                // and we haven't send anything to the user in a while (because of filtering, skipping, etc).
                                writer.WriteRaw(Environment.NewLine);
                                writer.Flush();
                                return(true);
                            }
                            processedDocuments++;


                            // We cant continue because we have already maxed out the batch bytes size.
                            if (options.MaxSize.HasValue && batchSize >= options.MaxSize)
                            {
                                return(false);
                            }

                            // We cant continue because we have already maxed out the amount of documents to send.
                            if (batchDocCount >= options.MaxDocCount)
                            {
                                return(false);
                            }

                            // We can continue because we are ignoring system documents.
                            if (doc.Key.StartsWith("Raven/", StringComparison.InvariantCultureIgnoreCase))
                            {
                                return(true);
                            }

                            // We can continue because we are ignoring the document as it doesn't fit the criteria.
                            if (MatchCriteria(criteria, doc) == false)
                            {
                                return(true);
                            }

                            doc.ToJson().WriteTo(writer);
                            writer.WriteRaw(Environment.NewLine);

                            batchSize += doc.SerializedSizeOnDisk;
                            batchDocCount++;

                            return(true); // We get the next document
                        };

                        int retries = 0;
                        do
                        {
                            int lastIndex = processedDocuments;

                            Database.TransactionalStorage.Batch(accessor =>
                            {
                                // we may be sending a LOT of documents to the user, and most
                                // of them aren't going to be relevant for other ops, so we are going to skip
                                // the cache for that, to avoid filling it up very quickly
                                using (DocumentCacher.SkipSetAndGetDocumentsInDocumentCache())
                                {
                                    if (isPrefixCriteria)
                                    {
                                        // If we don't get any document from GetDocumentsWithIdStartingWith it could be that we are in presence of a lagoon of uninteresting documents, so we are hitting a timeout.
                                        lastProcessedDocEtag = Database.Documents.GetDocumentsWithIdStartingWith(criteria.KeyStartsWith, options.MaxDocCount - batchDocCount, startEtag, cts.Token, addDocument);

                                        hasMoreDocs = false;
                                    }
                                    else
                                    {
                                        // It doesn't matter if we match the criteria or not, the document has been already processed.
                                        lastProcessedDocEtag = Database.Documents.GetDocuments(-1, options.MaxDocCount - batchDocCount, startEtag, cts.Token, addDocument);

                                        // If we don't get any document from GetDocuments it may be a signal that something is wrong.
                                        if (lastProcessedDocEtag == null)
                                        {
                                            hasMoreDocs = false;
                                        }
                                        else
                                        {
                                            var lastDocEtag = accessor.Staleness.GetMostRecentDocumentEtag();
                                            hasMoreDocs     = EtagUtil.IsGreaterThan(lastDocEtag, lastProcessedDocEtag);

                                            startEtag = lastProcessedDocEtag;
                                        }

                                        retries = lastIndex == batchDocCount ? retries : 0;
                                    }
                                }
                            });

                            if (lastIndex == processedDocuments)
                            {
                                if (retries == 3)
                                {
                                    log.Warn("Subscription processing did not end up replicating any documents for 3 times in a row, stopping operation", retries);
                                }
                                else
                                {
                                    log.Warn("Subscription processing did not end up replicating any documents, due to possible storage error, retry number: {0}", retries);
                                }
                                retries++;
                            }
                        }while (retries < 3 && hasMoreDocs && batchDocCount < options.MaxDocCount && (options.MaxSize.HasValue == false || batchSize < options.MaxSize));

                        writer.WriteEndArray();

                        if (batchDocCount > 0 || isPrefixCriteria)
                        {
                            writer.WritePropertyName("LastProcessedEtag");
                            writer.WriteValue(lastProcessedDocEtag.ToString());

                            sentDocuments = true;
                        }

                        writer.WriteEndObject();
                        writer.Flush();

                        bufferStream.Flush();
                    }
            }

            if (sentDocuments)
            {
                subscriptions.UpdateBatchSentTime(id);
            }
        }
예제 #3
0
        private void StreamToClient(Stream stream, string startsWith, int start, int pageSize, Etag etag, string matches, int nextPageStart, string skipAfter, string transformer, Dictionary <string, RavenJToken> transformerParameters,
                                    Lazy <NameValueCollection> headers, IPrincipal user)
        {
            var old     = CurrentOperationContext.Headers.Value;
            var oldUser = CurrentOperationContext.User.Value;

            try
            {
                CurrentOperationContext.Headers.Value = headers;
                CurrentOperationContext.User.Value    = user;


                var bufferStream = new BufferedStream(stream, 1024 * 64);
                using (var cts = new CancellationTokenSource())
                    using (var timeout = cts.TimeoutAfter(DatabasesLandlord.SystemConfiguration.DatabaseOperationTimeout))
                        using (var writer = new JsonTextWriter(new StreamWriter(bufferStream)))
                        {
                            writer.WriteStartObject();
                            writer.WritePropertyName("Results");
                            writer.WriteStartArray();

                            Action <JsonDocument> addDocument = doc =>
                            {
                                timeout.Delay();
                                if (doc == null)
                                {
                                    // we only have this heartbit when the streaming has gone on for a long time
                                    // and we haven't send anything to the user in a while (because of filtering, skipping, etc).
                                    writer.WriteRaw(Environment.NewLine);
                                    writer.Flush();
                                    return;
                                }
                                doc.ToJson().WriteTo(writer);
                                writer.WriteRaw(Environment.NewLine);
                            };

                            Database.TransactionalStorage.Batch(accessor =>
                            {
                                // we may be sending a LOT of documents to the user, and most
                                // of them aren't going to be relevant for other ops, so we are going to skip
                                // the cache for that, to avoid filling it up very quickly
                                using (DocumentCacher.SkipSetAndGetDocumentsInDocumentCache())
                                {
                                    if (string.IsNullOrEmpty(startsWith))
                                    {
                                        Database.Documents.GetDocuments(start, pageSize, etag, cts.Token, doc => { addDocument(doc); return(true); }, transformer, transformerParameters);
                                    }
                                    else
                                    {
                                        var nextPageStartInternal = nextPageStart;

                                        Database.Documents.GetDocumentsWithIdStartingWith(startsWith, matches, null, start, pageSize, cts.Token, ref nextPageStartInternal, addDocument, transformer, transformerParameters, skipAfter);

                                        nextPageStart = nextPageStartInternal;
                                    }
                                }
                            });

                            writer.WriteEndArray();
                            writer.WritePropertyName("NextPageStart");
                            writer.WriteValue(nextPageStart);
                            writer.WriteEndObject();
                            writer.Flush();
                            bufferStream.Flush();
                        }
            }
            finally
            {
                CurrentOperationContext.Headers.Value = old;
                CurrentOperationContext.User.Value    = oldUser;
            }
        }