ravendb /Raven.Database/Actions/LastCollectionEtags.cs

Language C# Lines 121
MD5 Hash e03d1458a0b123a1f96080a70b2ebe14
Repository https://github.com/nwendel/ravendb.git View Raw File
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Raven.Abstractions.Data;
using Raven.Abstractions.Extensions;
using Raven.Database.Indexing;
using Raven.Database.Linq;
using Raven.Database.Storage;
using Raven.Json.Linq;

namespace Raven.Database.Actions
{
    public class LastCollectionEtags
    {
	    private readonly WorkContext context;

	    public ITransactionalStorage TransactionalStorage { get; private set; }
        private readonly ConcurrentDictionary<string, Etag> lastCollectionEtags = new ConcurrentDictionary<string, Etag>();

        public LastCollectionEtags(ITransactionalStorage storage, WorkContext context)
        {
	        this.context = context;
	        this.TransactionalStorage = storage;
        }

	    public void Initialize()
        {
            TransactionalStorage.Batch(accessor =>
                accessor.Lists.Read("Raven/Collection/Etag", Etag.Empty, null, int.MaxValue)
                   .ForEach(x => lastCollectionEtags[x.Key] = Etag.Parse(x.Data.Value<string>("Etag"))));

            var lastKnownEtag = Etag.Empty;
            if (!lastCollectionEtags.TryGetValue("All", out lastKnownEtag))
                lastKnownEtag = Etag.Empty;
            var lastDatabaseEtag = Etag.Empty;
            TransactionalStorage.Batch(accessor => { lastDatabaseEtag = accessor.Staleness.GetMostRecentDocumentEtag(); });
            SeekMissingEtagsFrom(lastKnownEtag, lastDatabaseEtag);
        }

        private void SeekMissingEtagsFrom(Etag lastKnownEtag, Etag destinationEtag)
        {
            if (lastKnownEtag.CompareTo(destinationEtag) >= 0) return;

            TransactionalStorage.Batch(accessor =>
            {
                lastKnownEtag = UpdatePerCollectionEtags(
                    accessor.Documents.GetDocumentsAfter(lastKnownEtag, 1000, context.CancellationToken));
            });

            if(lastKnownEtag != null)
                SeekMissingEtagsFrom(lastKnownEtag, destinationEtag);
        }


        private void WriteLastEtagsForCollections()
        {
             TransactionalStorage.Batch(accessor => lastCollectionEtags.ForEach(x=> 
                     accessor.Lists.Set("Raven/Collection/Etag", x.Key, RavenJObject.FromObject(new { Etag = x.Value }), UuidType.Documents)));
        }

        public Etag ReadLastETagForCollection(string collectionName)
        {
            Etag value = Etag.Empty;
            TransactionalStorage.Batch(accessor =>
            {
                var dbvalue = accessor.Lists.Read("Raven/Collection/Etag", collectionName);
                if (dbvalue != null) value = Etag.Parse(dbvalue.Data.Value<string>("Etag"));
            });
            return value;
        }

        public Etag OptimizeCutoffForIndex(AbstractViewGenerator viewGenerator, Etag cutoffEtag)
        {
            if (cutoffEtag != null) return cutoffEtag;
            if (viewGenerator.ReduceDefinition == null && viewGenerator.ForEntityNames.Count > 0)
            {
                var etags = viewGenerator.ForEntityNames.Select(GetLastEtagForCollection)
                                        .Where(x=> x != null);
                if (etags.Any())
                    return etags.Max();
            }
            return null;
        }

        public Etag UpdatePerCollectionEtags(IEnumerable<JsonDocument> documents)
        {
            if (!documents.Any()) return null;

            var collections = documents.GroupBy(x => x.Metadata[Constants.RavenEntityName])
                .Where(x=>x.Key != null)
                .Select(x => new { Etag = x.Max(y => y.Etag), CollectionName = x.Key.ToString()})
                .ToArray();
             
            foreach (var collection in collections)
                UpdateLastEtagForCollection(collection.CollectionName, collection.Etag);

            var maximumEtag = documents.Max(x => x.Etag);
            UpdateLastEtagForCollection("All", maximumEtag);
            return maximumEtag;
        }

        private void UpdateLastEtagForCollection(string collectionName, Etag etag)
        {
            lastCollectionEtags.AddOrUpdate(collectionName, etag,
                (v, oldEtag) => etag.CompareTo(oldEtag) < 0 ? oldEtag : etag);
        }

        public Etag GetLastEtagForCollection(string collectionName)
        {
            Etag result = Etag.Empty;
            if (lastCollectionEtags.TryGetValue(collectionName, out result))
                return result;
            return null;
        }

        public void Flush()
        {
            this.WriteLastEtagsForCollections();
        }
    }
}
Back to Top