PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Raven.Database/Actions/LastCollectionEtags.cs

https://github.com/nwendel/ravendb
C# | 121 lines | 102 code | 19 blank | 0 comment | 16 complexity | e03d1458a0b123a1f96080a70b2ebe14 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-SA-3.0
  1. using System.Collections.Concurrent;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Raven.Abstractions.Data;
  5. using Raven.Abstractions.Extensions;
  6. using Raven.Database.Indexing;
  7. using Raven.Database.Linq;
  8. using Raven.Database.Storage;
  9. using Raven.Json.Linq;
  10. namespace Raven.Database.Actions
  11. {
  12. public class LastCollectionEtags
  13. {
  14. private readonly WorkContext context;
  15. public ITransactionalStorage TransactionalStorage { get; private set; }
  16. private readonly ConcurrentDictionary<string, Etag> lastCollectionEtags = new ConcurrentDictionary<string, Etag>();
  17. public LastCollectionEtags(ITransactionalStorage storage, WorkContext context)
  18. {
  19. this.context = context;
  20. this.TransactionalStorage = storage;
  21. }
  22. public void Initialize()
  23. {
  24. TransactionalStorage.Batch(accessor =>
  25. accessor.Lists.Read("Raven/Collection/Etag", Etag.Empty, null, int.MaxValue)
  26. .ForEach(x => lastCollectionEtags[x.Key] = Etag.Parse(x.Data.Value<string>("Etag"))));
  27. var lastKnownEtag = Etag.Empty;
  28. if (!lastCollectionEtags.TryGetValue("All", out lastKnownEtag))
  29. lastKnownEtag = Etag.Empty;
  30. var lastDatabaseEtag = Etag.Empty;
  31. TransactionalStorage.Batch(accessor => { lastDatabaseEtag = accessor.Staleness.GetMostRecentDocumentEtag(); });
  32. SeekMissingEtagsFrom(lastKnownEtag, lastDatabaseEtag);
  33. }
  34. private void SeekMissingEtagsFrom(Etag lastKnownEtag, Etag destinationEtag)
  35. {
  36. if (lastKnownEtag.CompareTo(destinationEtag) >= 0) return;
  37. TransactionalStorage.Batch(accessor =>
  38. {
  39. lastKnownEtag = UpdatePerCollectionEtags(
  40. accessor.Documents.GetDocumentsAfter(lastKnownEtag, 1000, context.CancellationToken));
  41. });
  42. if(lastKnownEtag != null)
  43. SeekMissingEtagsFrom(lastKnownEtag, destinationEtag);
  44. }
  45. private void WriteLastEtagsForCollections()
  46. {
  47. TransactionalStorage.Batch(accessor => lastCollectionEtags.ForEach(x=>
  48. accessor.Lists.Set("Raven/Collection/Etag", x.Key, RavenJObject.FromObject(new { Etag = x.Value }), UuidType.Documents)));
  49. }
  50. public Etag ReadLastETagForCollection(string collectionName)
  51. {
  52. Etag value = Etag.Empty;
  53. TransactionalStorage.Batch(accessor =>
  54. {
  55. var dbvalue = accessor.Lists.Read("Raven/Collection/Etag", collectionName);
  56. if (dbvalue != null) value = Etag.Parse(dbvalue.Data.Value<string>("Etag"));
  57. });
  58. return value;
  59. }
  60. public Etag OptimizeCutoffForIndex(AbstractViewGenerator viewGenerator, Etag cutoffEtag)
  61. {
  62. if (cutoffEtag != null) return cutoffEtag;
  63. if (viewGenerator.ReduceDefinition == null && viewGenerator.ForEntityNames.Count > 0)
  64. {
  65. var etags = viewGenerator.ForEntityNames.Select(GetLastEtagForCollection)
  66. .Where(x=> x != null);
  67. if (etags.Any())
  68. return etags.Max();
  69. }
  70. return null;
  71. }
  72. public Etag UpdatePerCollectionEtags(IEnumerable<JsonDocument> documents)
  73. {
  74. if (!documents.Any()) return null;
  75. var collections = documents.GroupBy(x => x.Metadata[Constants.RavenEntityName])
  76. .Where(x=>x.Key != null)
  77. .Select(x => new { Etag = x.Max(y => y.Etag), CollectionName = x.Key.ToString()})
  78. .ToArray();
  79. foreach (var collection in collections)
  80. UpdateLastEtagForCollection(collection.CollectionName, collection.Etag);
  81. var maximumEtag = documents.Max(x => x.Etag);
  82. UpdateLastEtagForCollection("All", maximumEtag);
  83. return maximumEtag;
  84. }
  85. private void UpdateLastEtagForCollection(string collectionName, Etag etag)
  86. {
  87. lastCollectionEtags.AddOrUpdate(collectionName, etag,
  88. (v, oldEtag) => etag.CompareTo(oldEtag) < 0 ? oldEtag : etag);
  89. }
  90. public Etag GetLastEtagForCollection(string collectionName)
  91. {
  92. Etag result = Etag.Empty;
  93. if (lastCollectionEtags.TryGetValue(collectionName, out result))
  94. return result;
  95. return null;
  96. }
  97. public void Flush()
  98. {
  99. this.WriteLastEtagsForCollections();
  100. }
  101. }
  102. }