forked from ravendb/ravendb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
AttachmentsStorageActions.cs
127 lines (116 loc) · 4.13 KB
/
AttachmentsStorageActions.cs
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
122
123
124
125
126
127
//-----------------------------------------------------------------------
// <copyright file="AttachmentsStorageActions.cs" company="Hibernating Rhinos LTD">
// Copyright (c) Hibernating Rhinos LTD. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using NLog;
using Raven.Abstractions.Data;
using Raven.Abstractions.Exceptions;
using Raven.Abstractions.Extensions;
using Raven.Database.Data;
using Raven.Database.Impl;
using Raven.Database.Storage;
using Raven.Json.Linq;
using Raven.Storage.Managed.Impl;
namespace Raven.Storage.Managed
{
public class AttachmentsStorageActions : IAttachmentsStorageActions
{
private readonly TableStorage storage;
private readonly IUuidGenerator generator;
private static readonly Logger logger = LogManager.GetCurrentClassLogger();
public AttachmentsStorageActions(TableStorage storage, IUuidGenerator generator)
{
this.storage = storage;
this.generator = generator;
}
public Guid AddAttachment(string key, Guid? etag, Stream data, RavenJObject headers)
{
AssertValidEtag(key, etag, "PUT");
var ms = new MemoryStream();
headers.WriteTo(ms);
data.CopyTo(ms);
var newEtag = generator.CreateSequentialUuid();
var result = storage.Attachments.Put(new RavenJObject
{
{"key", key},
{"etag", newEtag.ToByteArray()}
}, ms.ToArray());
if (result == false)
throw new ConcurrencyException("PUT attempted on attachment '" + key + "' while it was locked by another transaction");
logger.Debug("Adding attachment {0}", key);
return newEtag;
}
private void AssertValidEtag(string key, Guid? etag, string op)
{
var readResult =
storage.Attachments.Read(new RavenJObject { { "key", key } });
if(readResult != null && etag != null)
{
var existingEtag = new Guid(readResult.Key.Value<byte[]>("etag"));
if (existingEtag != etag)
{
throw new ConcurrencyException(op + " attempted on attachment '" + key +
"' using a non current etag")
{
ActualETag = existingEtag,
ExpectedETag = etag.Value
};
}
}
}
public void DeleteAttachment(string key, Guid? etag)
{
AssertValidEtag(key, etag, "DELETE");
if (!storage.Attachments.Remove(new RavenJObject { { "key", key } }))
throw new ConcurrencyException("DELETE attempted on attachment '" + key +
"' while it was locked by another transaction");
logger.Debug("Attachment with key '{0}' was deleted", key);
}
public Attachment GetAttachment(string key)
{
var readResult = storage.Attachments.Read(new RavenJObject { { "key", key } });
if (readResult == null)
return null;
var attachmentDAta = readResult.Data();
var memoryStream = new MemoryStream(attachmentDAta);
var metadata = memoryStream.ToJObject();
return new Attachment
{
Etag = new Guid(readResult.Key.Value<byte[]>("etag")),
Metadata = metadata,
Data = () => memoryStream,
Size = (int)(memoryStream.Length - memoryStream.Position)
};
}
public IEnumerable<AttachmentInformation> GetAttachmentsByReverseUpdateOrder(int start)
{
return from key in storage.Attachments["ByEtag"].SkipFromEnd(start)
let attachment = GetAttachment(key.Value<string>("key"))
select new AttachmentInformation
{
Key = key.Value<string>("key"),
Etag = new Guid(key.Value<byte[]>("etag")),
Metadata = attachment.Metadata,
Size = attachment.Size
};
}
public IEnumerable<AttachmentInformation> GetAttachmentsAfter(Guid value)
{
return from key in storage.Attachments["ByEtag"]
.SkipAfter(new RavenJObject{{"etag", value.ToByteArray()}})
let attachment = GetAttachment(key.Value<string>("key"))
select new AttachmentInformation
{
Key = key.Value<string>("key"),
Etag = new Guid(key.Value<byte[]>("etag")),
Metadata = attachment.Metadata,
Size = attachment.Size
};
}
}
}