PageRenderTime 46ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/Raven.Database/Bundles/Replication/Responders/Behaviors/AttachmentReplicationBehavior.cs

https://github.com/nwendel/ravendb
C# | 143 lines | 124 code | 18 blank | 1 comment | 7 complexity | 2d16a3cba426637bcb81c4e6a0e9a986 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-SA-3.0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using Raven.Abstractions.Data;
  6. using Raven.Abstractions.Extensions;
  7. using Raven.Bundles.Replication.Plugins;
  8. using Raven.Database.Impl;
  9. using Raven.Json.Linq;
  10. namespace Raven.Bundles.Replication.Responders
  11. {
  12. public class AttachmentReplicationBehavior : SingleItemReplicationBehavior<Attachment, byte[]>
  13. {
  14. public IEnumerable<AbstractAttachmentReplicationConflictResolver> ReplicationConflictResolvers { get; set; }
  15. protected override ReplicationConflictTypes ReplicationConflict
  16. {
  17. get { return ReplicationConflictTypes.AttachmentReplicationConflict; }
  18. }
  19. protected override void DeleteItem(string id, Etag etag)
  20. {
  21. Database.Attachments.DeleteStatic(id, etag);
  22. }
  23. protected override void MarkAsDeleted(string id, RavenJObject metadata)
  24. {
  25. Actions.Lists.Set(Constants.RavenReplicationAttachmentsTombstones, id, metadata, UuidType.Attachments);
  26. }
  27. protected override void AddWithoutConflict(string id, Etag etag, RavenJObject metadata, byte[] incoming)
  28. {
  29. Database.Attachments.PutStatic(id, etag, new MemoryStream(incoming), metadata);
  30. Actions.Lists.Remove(Constants.RavenReplicationAttachmentsTombstones, id);
  31. }
  32. protected override CreatedConflict CreateConflict(string id, string newDocumentConflictId, string existingDocumentConflictId, Attachment existingItem, RavenJObject existingMetadata)
  33. {
  34. existingItem.Metadata.Add(Constants.RavenReplicationConflict, RavenJToken.FromObject(true));
  35. Actions.Attachments.AddAttachment(existingDocumentConflictId, null, existingItem.Data(), existingItem.Metadata);
  36. Actions.Lists.Remove(Constants.RavenReplicationDocsTombstones, id);
  37. var conflictsArray = new RavenJArray(existingDocumentConflictId, newDocumentConflictId);
  38. var conflictAttachment = new RavenJObject
  39. {
  40. {"Conflicts", conflictsArray}
  41. };
  42. var memoryStream = new MemoryStream();
  43. conflictAttachment.WriteTo(memoryStream);
  44. memoryStream.Position = 0;
  45. var etag = existingMetadata.Value<bool>(Constants.RavenDeleteMarker) ? null : existingItem.Etag;
  46. var newEtag = Actions.Attachments.AddAttachment(id, etag,
  47. memoryStream,
  48. new RavenJObject
  49. {
  50. {Constants.RavenReplicationConflict, true},
  51. {"@Http-Status-Code", 409},
  52. {"@Http-Status-Description", "Conflict"}
  53. });
  54. return new CreatedConflict()
  55. {
  56. Etag = newEtag,
  57. ConflictedIds = conflictsArray.Select(x => x.Value<string>()).ToArray()
  58. };
  59. }
  60. protected override CreatedConflict AppendToCurrentItemConflicts(string id, string newConflictId, RavenJObject existingMetadata, Attachment existingItem)
  61. {
  62. var existingConflict = existingItem.Data().ToJObject();
  63. // just update the current attachment with the new conflict document
  64. RavenJArray conflictArray;
  65. existingConflict["Conflicts"] = conflictArray = new RavenJArray(existingConflict.Value<RavenJArray>("Conflicts"));
  66. var conflictEtag = existingItem.Etag;
  67. if (conflictArray.Contains(newConflictId) == false)
  68. {
  69. conflictArray.Add(newConflictId);
  70. var memoryStream = new MemoryStream();
  71. existingConflict.WriteTo(memoryStream);
  72. memoryStream.Position = 0;
  73. var newETag = Actions.Attachments.AddAttachment(id, existingItem.Etag, memoryStream, existingItem.Metadata);
  74. conflictEtag = newETag;
  75. }
  76. return new CreatedConflict
  77. {
  78. Etag = conflictEtag,
  79. ConflictedIds = conflictArray.Select(x => x.Value<string>()).ToArray()
  80. };
  81. }
  82. protected override RavenJObject TryGetExisting(string id, out Attachment existingItem, out Etag existingEtag, out bool deleted)
  83. {
  84. var existingAttachment = Actions.Attachments.GetAttachment(id);
  85. if (existingAttachment != null)
  86. {
  87. existingItem = existingAttachment;
  88. existingEtag = existingAttachment.Etag;
  89. deleted = false;
  90. return existingAttachment.Metadata;
  91. }
  92. var listItem = Actions.Lists.Read(Constants.RavenReplicationAttachmentsTombstones, id);
  93. if (listItem != null)
  94. {
  95. existingEtag = listItem.Etag;
  96. existingItem = new Attachment
  97. {
  98. Etag = listItem.Etag,
  99. Key = listItem.Key,
  100. Metadata = listItem.Data,
  101. Data = () => new MemoryStream()
  102. };
  103. deleted = true;
  104. return listItem.Data;
  105. }
  106. deleted = false;
  107. existingEtag = Etag.Empty;
  108. existingItem = null;
  109. return null;
  110. }
  111. protected override bool TryResolveConflict(string id, RavenJObject metadata, byte[] data, Attachment existing, out RavenJObject metadataToSave,
  112. out byte[] dataToSave)
  113. {
  114. foreach (var replicationConflictResolver in ReplicationConflictResolvers)
  115. {
  116. if (replicationConflictResolver.TryResolve(id, metadata, data, existing, Actions.Attachments.GetAttachment,
  117. out metadataToSave, out dataToSave))
  118. return true;
  119. }
  120. metadataToSave = null;
  121. dataToSave = null;
  122. return false;
  123. }
  124. }
  125. }