-
Notifications
You must be signed in to change notification settings - Fork 820
/
AttachmentsStorageActions.cs
131 lines (120 loc) · 5.19 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
128
129
130
131
//-----------------------------------------------------------------------
// <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 log4net;
using Newtonsoft.Json.Linq;
using Raven.Abstractions.Data;
using Raven.Abstractions.Exceptions;
using Raven.Abstractions.Extensions;
using Raven.Database.Data;
using Raven.Database.Impl;
using Raven.Database.Json;
using Raven.Database.Storage;
using Raven.Http.Exceptions;
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 readonly ILog logger = LogManager.GetLogger(typeof (AttachmentsStorageActions));
public AttachmentsStorageActions(TableStorage storage, IUuidGenerator generator)
{
this.storage = storage;
this.generator = generator;
}
public Guid AddAttachment(string key, Guid? etag, byte[] data, RavenJObject headers)
{
AssertValidEtag(key, etag, "PUT");
var ms = new MemoryStream();
headers.WriteTo(ms);
ms.Write(data,0,data.Length);
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.DebugFormat("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 = etag.Value,
ExpectedETag = existingEtag
};
}
}
}
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.DebugFormat("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();
var data = new byte[readResult.Size - memoryStream.Position];
Buffer.BlockCopy(attachmentDAta,(int)memoryStream.Position, data, 0, data.Length);
return new Attachment
{
Etag = new Guid(readResult.Key.Value<byte[]>("etag")),
Metadata = metadata,
Data = data
};
}
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.Data.Length
};
}
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.Data.Length
};
}
}
}