PageRenderTime 58ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/Raven.Database/Storage/Voron/StorageActions/MappedResultsStorageActions.cs

https://github.com/nwendel/ravendb
C# | 1076 lines | 888 code | 188 blank | 0 comment | 95 complexity | f08086055baf43cdd977b4080f0e5734 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, BSD-3-Clause, CC-BY-SA-3.0
  1. using System.Diagnostics;
  2. using System.Text;
  3. using Raven.Abstractions.Util.Encryptors;
  4. using Raven.Abstractions.Util.Streams;
  5. using Raven.Database.Util;
  6. namespace Raven.Database.Storage.Voron.StorageActions
  7. {
  8. using System;
  9. using System.Collections.Generic;
  10. using System.Globalization;
  11. using System.IO;
  12. using System.Linq;
  13. using Raven.Abstractions;
  14. using Raven.Abstractions.Data;
  15. using Raven.Abstractions.Extensions;
  16. using Raven.Abstractions.MEF;
  17. using Raven.Database.Impl;
  18. using Raven.Database.Indexing;
  19. using Raven.Database.Plugins;
  20. using Raven.Database.Storage.Voron.Impl;
  21. using Raven.Json.Linq;
  22. using global::Voron;
  23. using global::Voron.Impl;
  24. using Index = Raven.Database.Storage.Voron.Impl.Index;
  25. public class MappedResultsStorageActions : StorageActionsBase, IMappedResultsStorageAction
  26. {
  27. private readonly TableStorage tableStorage;
  28. private readonly IUuidGenerator generator;
  29. private readonly Reference<WriteBatch> writeBatch;
  30. private readonly OrderedPartCollection<AbstractDocumentCodec> documentCodecs;
  31. public MappedResultsStorageActions(TableStorage tableStorage, IUuidGenerator generator, OrderedPartCollection<AbstractDocumentCodec> documentCodecs, Reference<SnapshotReader> snapshot, Reference<WriteBatch> writeBatch, IBufferPool bufferPool)
  32. : base(snapshot, bufferPool)
  33. {
  34. this.tableStorage = tableStorage;
  35. this.generator = generator;
  36. this.documentCodecs = documentCodecs;
  37. this.writeBatch = writeBatch;
  38. }
  39. public IEnumerable<ReduceKeyAndCount> GetKeysStats(int view, int start, int pageSize)
  40. {
  41. var reduceKeyCountsByView = tableStorage.ReduceKeyCounts.GetIndex(Tables.ReduceKeyCounts.Indices.ByView);
  42. using (var iterator = reduceKeyCountsByView.MultiRead(Snapshot, CreateKey(view)))
  43. {
  44. if (!iterator.Seek(Slice.BeforeAllKeys) || !iterator.Skip(start))
  45. yield break;
  46. var count = 0;
  47. do
  48. {
  49. ushort version;
  50. var value = LoadJson(tableStorage.ReduceKeyCounts, iterator.CurrentKey, writeBatch.Value, out version);
  51. Debug.Assert(value != null);
  52. yield return new ReduceKeyAndCount
  53. {
  54. Count = value.Value<int>("mappedItemsCount"),
  55. Key = value.Value<string>("reduceKey")
  56. };
  57. count++;
  58. }
  59. while (iterator.MoveNext() && count < pageSize);
  60. }
  61. }
  62. public void PutMappedResult(int view, string docId, string reduceKey, RavenJObject data)
  63. {
  64. var mappedResultsByViewAndDocumentId = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndDocumentId);
  65. var mappedResultsByView = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByView);
  66. var mappedResultsByViewAndReduceKey = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKey);
  67. var mappedResultsByViewAndReduceKeyAndSourceBucket = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKeyAndSourceBucket);
  68. var mappedResultsData = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.Data);
  69. var ms = CreateStream();
  70. using (var stream = documentCodecs.Aggregate((Stream) new UndisposableStream(ms), (ds, codec) => codec.Value.Encode(reduceKey, data, null, ds)))
  71. {
  72. data.WriteTo(stream);
  73. stream.Flush();
  74. }
  75. var id = generator.CreateSequentialUuid(UuidType.MappedResults);
  76. var idAsString = id.ToString();
  77. var bucket = IndexingUtil.MapBucket(docId);
  78. var reduceKeyHash = HashKey(reduceKey);
  79. tableStorage.MappedResults.Add(
  80. writeBatch.Value,
  81. idAsString,
  82. new RavenJObject
  83. {
  84. { "view", view },
  85. { "reduceKey", reduceKey },
  86. { "docId", docId },
  87. { "etag", id.ToByteArray() },
  88. { "bucket", bucket },
  89. { "timestamp", SystemTime.UtcNow }
  90. }, 0);
  91. ms.Position = 0;
  92. mappedResultsData.Add(writeBatch.Value, idAsString, ms, 0);
  93. mappedResultsByViewAndDocumentId.MultiAdd(writeBatch.Value, CreateKey(view, docId), idAsString);
  94. mappedResultsByView.MultiAdd(writeBatch.Value, CreateKey(view), idAsString);
  95. mappedResultsByViewAndReduceKey.MultiAdd(writeBatch.Value, CreateKey(view, reduceKey, reduceKeyHash), idAsString);
  96. mappedResultsByViewAndReduceKeyAndSourceBucket.MultiAdd(writeBatch.Value, CreateKey(view, reduceKey, reduceKeyHash, bucket), idAsString);
  97. }
  98. public void IncrementReduceKeyCounter(int view, string reduceKey, int val)
  99. {
  100. var reduceKeyHash = HashKey(reduceKey);
  101. var key = CreateKey(view, reduceKey, reduceKeyHash);
  102. ushort version;
  103. var value = LoadJson(tableStorage.ReduceKeyCounts, key, writeBatch.Value, out version);
  104. var newValue = val;
  105. if (value != null)
  106. newValue += value.Value<int>("mappedItemsCount");
  107. AddReduceKeyCount(key, view, reduceKey, newValue, version);
  108. }
  109. private void DecrementReduceKeyCounter(int view, string reduceKey, int val)
  110. {
  111. var reduceKeyHash = HashKey(reduceKey);
  112. var key = CreateKey(view, reduceKey, reduceKeyHash);
  113. ushort reduceKeyCountVersion;
  114. var reduceKeyCount = LoadJson(tableStorage.ReduceKeyCounts, key, writeBatch.Value, out reduceKeyCountVersion);
  115. var newValue = -val;
  116. if (reduceKeyCount != null)
  117. {
  118. var currentValue = reduceKeyCount.Value<int>("mappedItemsCount");
  119. if (currentValue == val)
  120. {
  121. var reduceKeyTypeVersion = tableStorage.ReduceKeyTypes.ReadVersion(Snapshot, key);
  122. DeleteReduceKeyCount(key, view, reduceKeyCountVersion);
  123. DeleteReduceKeyType(key, view, reduceKeyTypeVersion);
  124. return;
  125. }
  126. newValue += currentValue;
  127. }
  128. AddReduceKeyCount(key, view, reduceKey, newValue, reduceKeyCountVersion);
  129. }
  130. public void DeleteMappedResultsForDocumentId(string documentId, int view, Dictionary<ReduceKeyAndBucket, int> removed)
  131. {
  132. var viewAndDocumentId = CreateKey(view, documentId);
  133. var mappedResultsByViewAndDocumentId = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndDocumentId);
  134. using (var iterator = mappedResultsByViewAndDocumentId.MultiRead(Snapshot, viewAndDocumentId))
  135. {
  136. if (!iterator.Seek(Slice.BeforeAllKeys))
  137. return;
  138. do
  139. {
  140. var id = iterator.CurrentKey.Clone();
  141. ushort version;
  142. var value = LoadJson(tableStorage.MappedResults, id, writeBatch.Value, out version);
  143. var reduceKey = value.Value<string>("reduceKey");
  144. var bucket = value.Value<int>("bucket");
  145. DeleteMappedResult(id, view, documentId, reduceKey, bucket.ToString(CultureInfo.InvariantCulture));
  146. var reduceKeyAndBucket = new ReduceKeyAndBucket(bucket, reduceKey);
  147. removed[reduceKeyAndBucket] = removed.GetOrDefault(reduceKeyAndBucket) + 1;
  148. }
  149. while (iterator.MoveNext());
  150. }
  151. }
  152. public void UpdateRemovedMapReduceStats(int view, Dictionary<ReduceKeyAndBucket, int> removed)
  153. {
  154. foreach (var keyAndBucket in removed)
  155. {
  156. DecrementReduceKeyCounter(view, keyAndBucket.Key.ReduceKey, keyAndBucket.Value);
  157. }
  158. }
  159. public void DeleteMappedResultsForView(int view)
  160. {
  161. var deletedReduceKeys = new List<string>();
  162. var mappedResultsByView = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByView);
  163. using (var iterator = mappedResultsByView.MultiRead(Snapshot, CreateKey(view)))
  164. {
  165. if (!iterator.Seek(Slice.BeforeAllKeys))
  166. return;
  167. do
  168. {
  169. var id = iterator.CurrentKey.Clone();
  170. ushort version;
  171. var value = LoadJson(tableStorage.MappedResults, id, writeBatch.Value, out version);
  172. var reduceKey = value.Value<string>("reduceKey");
  173. var bucket = value.Value<string>("bucket");
  174. DeleteMappedResult(id, view, value.Value<string>("docId"), reduceKey, bucket);
  175. deletedReduceKeys.Add(reduceKey);
  176. }
  177. while (iterator.MoveNext());
  178. }
  179. foreach (var g in deletedReduceKeys.GroupBy(x => x, StringComparer.InvariantCultureIgnoreCase))
  180. {
  181. DecrementReduceKeyCounter(view, g.Key, g.Count());
  182. }
  183. }
  184. public IEnumerable<string> GetKeysForIndexForDebug(int view, string startsWith, string sourceId, int start, int take)
  185. {
  186. var mappedResultsByView = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByView);
  187. using (var iterator = mappedResultsByView.MultiRead(Snapshot, CreateKey(view)))
  188. {
  189. if (!iterator.Seek(Slice.BeforeAllKeys))
  190. return Enumerable.Empty<string>();
  191. var results = new List<string>();
  192. do
  193. {
  194. ushort version;
  195. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  196. if (string.IsNullOrEmpty(sourceId) == false)
  197. {
  198. var docId = value.Value<string>("docId");
  199. if (string.Equals(sourceId, docId, StringComparison.OrdinalIgnoreCase) == false)
  200. continue;
  201. }
  202. var reduceKey = value.Value<string>("reduceKey");
  203. if (string.IsNullOrEmpty(startsWith) == false && reduceKey.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase) == false)
  204. continue;
  205. results.Add(reduceKey);
  206. }
  207. while (iterator.MoveNext());
  208. return results
  209. .Distinct()
  210. .Skip(start)
  211. .Take(take);
  212. }
  213. }
  214. public IEnumerable<MappedResultInfo> GetMappedResultsForDebug(int view, string reduceKey, int start, int take)
  215. {
  216. var reduceKeyHash = HashKey(reduceKey);
  217. var viewAndReduceKey = CreateKey(view, reduceKey, reduceKeyHash);
  218. var mappedResultsByViewAndReduceKey = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKey);
  219. var mappedResultsData = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.Data);
  220. using (var iterator = mappedResultsByViewAndReduceKey.MultiRead(Snapshot, viewAndReduceKey))
  221. {
  222. if (!iterator.Seek(Slice.BeforeAllKeys) || !iterator.Skip(start))
  223. yield break;
  224. var count = 0;
  225. do
  226. {
  227. ushort version;
  228. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  229. var size = tableStorage.MappedResults.GetDataSize(Snapshot, iterator.CurrentKey);
  230. yield return new MappedResultInfo
  231. {
  232. ReduceKey = value.Value<string>("reduceKey"),
  233. Etag = Etag.Parse(value.Value<byte[]>("etag")),
  234. Timestamp = value.Value<DateTime>("timestamp"),
  235. Bucket = value.Value<int>("bucket"),
  236. Source = value.Value<string>("docId"),
  237. Size = size,
  238. Data = LoadMappedResult(iterator.CurrentKey, value, mappedResultsData)
  239. };
  240. count++;
  241. }
  242. while (iterator.MoveNext() && count < take);
  243. }
  244. }
  245. public IEnumerable<string> GetSourcesForIndexForDebug(int view, string startsWith, int take)
  246. {
  247. var mappedResultsByView = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByView);
  248. using (var iterator = mappedResultsByView.MultiRead(Snapshot, CreateKey(view)))
  249. {
  250. if (!iterator.Seek(Slice.BeforeAllKeys))
  251. return Enumerable.Empty<string>();
  252. var results = new HashSet<string>();
  253. do
  254. {
  255. ushort version;
  256. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  257. var docId = value.Value<string>("docId");
  258. if (string.IsNullOrEmpty(startsWith) == false && docId.StartsWith(startsWith, StringComparison.OrdinalIgnoreCase) == false)
  259. continue;
  260. results.Add(docId);
  261. }
  262. while (iterator.MoveNext() && results.Count <= take);
  263. return results;
  264. }
  265. }
  266. public IEnumerable<MappedResultInfo> GetReducedResultsForDebug(int view, string reduceKey, int level, int start, int take)
  267. {
  268. var reduceKeyHash = HashKey(reduceKey);
  269. var viewAndReduceKeyAndLevel = CreateKey(view, reduceKey, reduceKeyHash, level);
  270. var reduceResultsByViewAndReduceKeyAndLevel =
  271. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevel);
  272. var reduceResultsData = tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.Data);
  273. using (var iterator = reduceResultsByViewAndReduceKeyAndLevel.MultiRead(Snapshot, viewAndReduceKeyAndLevel))
  274. {
  275. if (!iterator.Seek(Slice.BeforeAllKeys) || !iterator.Skip(start))
  276. yield break;
  277. var count = 0;
  278. do
  279. {
  280. ushort version;
  281. var value = LoadJson(tableStorage.ReduceResults, iterator.CurrentKey, writeBatch.Value, out version);
  282. var size = tableStorage.ReduceResults.GetDataSize(Snapshot, iterator.CurrentKey);
  283. yield return
  284. new MappedResultInfo
  285. {
  286. ReduceKey = value.Value<string>("reduceKey"),
  287. Etag = Etag.Parse(value.Value<byte[]>("etag")),
  288. Timestamp = value.Value<DateTime>("timestamp"),
  289. Bucket = value.Value<int>("bucket"),
  290. Source = value.Value<string>("sourceBucket"),
  291. Size = size,
  292. Data = LoadMappedResult(iterator.CurrentKey, value, reduceResultsData)
  293. };
  294. count++;
  295. }
  296. while (iterator.MoveNext() && count < take);
  297. }
  298. }
  299. public IEnumerable<ScheduledReductionDebugInfo> GetScheduledReductionForDebug(int view, int start, int take)
  300. {
  301. var scheduledReductionsByView = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByView);
  302. using (var iterator = scheduledReductionsByView.MultiRead(Snapshot, CreateKey(view)))
  303. {
  304. if (!iterator.Seek(Slice.BeforeAllKeys) || !iterator.Skip(start))
  305. yield break;
  306. var count = 0;
  307. do
  308. {
  309. ushort version;
  310. var value = LoadJson(tableStorage.ScheduledReductions, iterator.CurrentKey, writeBatch.Value, out version);
  311. yield return new ScheduledReductionDebugInfo
  312. {
  313. Key = value.Value<string>("reduceKey"),
  314. Bucket = value.Value<int>("bucket"),
  315. Etag = new Guid(value.Value<byte[]>("etag")),
  316. Level = value.Value<int>("level"),
  317. Timestamp = value.Value<DateTime>("timestamp"),
  318. };
  319. count++;
  320. }
  321. while (iterator.MoveNext() && count < take);
  322. }
  323. }
  324. public void ScheduleReductions(int view, int level, ReduceKeyAndBucket reduceKeysAndBuckets)
  325. {
  326. var scheduledReductionsByView = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByView);
  327. var scheduledReductionsByViewAndLevelAndReduceKey = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByViewAndLevelAndReduceKey);
  328. var id = generator.CreateSequentialUuid(UuidType.ScheduledReductions);
  329. var idAsString = id.ToString();
  330. var reduceHashKey = HashKey(reduceKeysAndBuckets.ReduceKey);
  331. tableStorage.ScheduledReductions.Add(writeBatch.Value, idAsString, new RavenJObject
  332. {
  333. {"view", view},
  334. {"reduceKey", reduceKeysAndBuckets.ReduceKey},
  335. {"bucket", reduceKeysAndBuckets.Bucket},
  336. {"level", level},
  337. {"etag", id.ToByteArray()},
  338. {"timestamp", SystemTime.UtcNow}
  339. });
  340. scheduledReductionsByView.MultiAdd(writeBatch.Value, CreateKey(view), idAsString);
  341. scheduledReductionsByViewAndLevelAndReduceKey.MultiAdd(writeBatch.Value, CreateKey(view, level, reduceKeysAndBuckets.ReduceKey, reduceHashKey), idAsString);
  342. }
  343. public IEnumerable<MappedResultInfo> GetItemsToReduce(GetItemsToReduceParams getItemsToReduceParams)
  344. {
  345. var scheduledReductionsByViewAndLevelAndReduceKey = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByViewAndLevelAndReduceKey);
  346. var deleter = new ScheduledReductionDeleter(getItemsToReduceParams.ItemsToDelete, o =>
  347. {
  348. var json = o as RavenJObject;
  349. if (json == null)
  350. return null;
  351. var etag = Etag.Parse(json.Value<byte[]>("etag"));
  352. return etag.ToString();
  353. });
  354. var seenLocally = new HashSet<Tuple<string, int>>();
  355. foreach (var reduceKey in getItemsToReduceParams.ReduceKeys.ToArray())
  356. {
  357. var reduceKeyHash = HashKey(reduceKey);
  358. var viewAndLevelAndReduceKey = CreateKey(getItemsToReduceParams.Index, getItemsToReduceParams.Level, reduceKey, reduceKeyHash);
  359. using (var iterator = scheduledReductionsByViewAndLevelAndReduceKey.MultiRead(Snapshot, viewAndLevelAndReduceKey))
  360. {
  361. if (!iterator.Seek(Slice.BeforeAllKeys))
  362. continue;
  363. do
  364. {
  365. if (getItemsToReduceParams.Take <= 0)
  366. break;
  367. ushort version;
  368. var value = LoadJson(tableStorage.ScheduledReductions, iterator.CurrentKey, writeBatch.Value, out version);
  369. var reduceKeyFromDb = value.Value<string>("reduceKey");
  370. var bucket = value.Value<int>("bucket");
  371. var rowKey = Tuple.Create(reduceKeyFromDb, bucket);
  372. var thisIsNewScheduledReductionRow = deleter.Delete(iterator.CurrentKey, value);
  373. var neverSeenThisKeyAndBucket = getItemsToReduceParams.ItemsAlreadySeen.Add(rowKey);
  374. if (thisIsNewScheduledReductionRow || neverSeenThisKeyAndBucket)
  375. {
  376. if (seenLocally.Add(rowKey))
  377. {
  378. foreach (var mappedResultInfo in GetResultsForBucket(getItemsToReduceParams.Index, getItemsToReduceParams.Level, reduceKeyFromDb, bucket, getItemsToReduceParams.LoadData))
  379. {
  380. getItemsToReduceParams.Take--;
  381. yield return mappedResultInfo;
  382. }
  383. }
  384. }
  385. if (getItemsToReduceParams.Take <= 0)
  386. yield break;
  387. }
  388. while (iterator.MoveNext());
  389. }
  390. getItemsToReduceParams.ReduceKeys.Remove(reduceKey);
  391. if (getItemsToReduceParams.Take <= 0)
  392. yield break;
  393. }
  394. }
  395. private IEnumerable<MappedResultInfo> GetResultsForBucket(int view, int level, string reduceKey, int bucket, bool loadData)
  396. {
  397. switch (level)
  398. {
  399. case 0:
  400. return GetMappedResultsForBucket(view, reduceKey, bucket, loadData);
  401. case 1:
  402. case 2:
  403. return GetReducedResultsForBucket(view, reduceKey, level, bucket, loadData);
  404. default:
  405. throw new ArgumentException("Invalid level: " + level);
  406. }
  407. }
  408. private IEnumerable<MappedResultInfo> GetReducedResultsForBucket(int view, string reduceKey, int level, int bucket, bool loadData)
  409. {
  410. var reduceKeyHash = HashKey(reduceKey);
  411. var viewAndReduceKeyAndLevelAndBucket = CreateKey(view, reduceKey, reduceKeyHash, level, bucket);
  412. var reduceResultsByViewAndReduceKeyAndLevelAndBucket = tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndBucket);
  413. var reduceResultsData = tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.Data);
  414. using (var iterator = reduceResultsByViewAndReduceKeyAndLevelAndBucket.MultiRead(Snapshot, viewAndReduceKeyAndLevelAndBucket))
  415. {
  416. if (!iterator.Seek(Slice.BeforeAllKeys))
  417. {
  418. yield return new MappedResultInfo
  419. {
  420. Bucket = bucket,
  421. ReduceKey = reduceKey
  422. };
  423. yield break;
  424. }
  425. do
  426. {
  427. ushort version;
  428. var value = LoadJson(tableStorage.ReduceResults, iterator.CurrentKey, writeBatch.Value, out version);
  429. var size = tableStorage.ReduceResults.GetDataSize(Snapshot, iterator.CurrentKey);
  430. yield return new MappedResultInfo
  431. {
  432. ReduceKey = value.Value<string>("reduceKey"),
  433. Etag = Etag.Parse(value.Value<byte[]>("etag")),
  434. Timestamp = value.Value<DateTime>("timestamp"),
  435. Bucket = value.Value<int>("bucket"),
  436. Source = null,
  437. Size = size,
  438. Data = loadData ? LoadMappedResult(iterator.CurrentKey, value, reduceResultsData) : null
  439. };
  440. }
  441. while (iterator.MoveNext());
  442. }
  443. }
  444. private IEnumerable<MappedResultInfo> GetMappedResultsForBucket(int view, string reduceKey, int bucket, bool loadData)
  445. {
  446. var reduceKeyHash = HashKey(reduceKey);
  447. var viewAndReduceKeyAndSourceBucket = CreateKey(view, reduceKey, reduceKeyHash, bucket);
  448. var mappedResultsByViewAndReduceKeyAndSourceBucket = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKeyAndSourceBucket);
  449. var mappedResultsData = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.Data);
  450. using (var iterator = mappedResultsByViewAndReduceKeyAndSourceBucket.MultiRead(Snapshot, viewAndReduceKeyAndSourceBucket))
  451. {
  452. if (!iterator.Seek(Slice.BeforeAllKeys))
  453. {
  454. yield return new MappedResultInfo
  455. {
  456. Bucket = bucket,
  457. ReduceKey = reduceKey
  458. };
  459. yield break;
  460. }
  461. do
  462. {
  463. ushort version;
  464. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  465. var size = tableStorage.MappedResults.GetDataSize(Snapshot, iterator.CurrentKey);
  466. yield return new MappedResultInfo
  467. {
  468. ReduceKey = value.Value<string>("reduceKey"),
  469. Etag = Etag.Parse(value.Value<byte[]>("etag")),
  470. Timestamp = value.Value<DateTime>("timestamp"),
  471. Bucket = value.Value<int>("bucket"),
  472. Source = null,
  473. Size = size,
  474. Data = loadData ? LoadMappedResult(iterator.CurrentKey, value, mappedResultsData) : null
  475. };
  476. }
  477. while (iterator.MoveNext());
  478. }
  479. }
  480. public ScheduledReductionInfo DeleteScheduledReduction(IEnumerable<object> itemsToDelete)
  481. {
  482. if (itemsToDelete == null)
  483. return null;
  484. var result = new ScheduledReductionInfo();
  485. var hasResult = false;
  486. var currentEtag = Etag.Empty;
  487. foreach (RavenJToken token in itemsToDelete)
  488. {
  489. var etag = Etag.Parse(token.Value<byte[]>("etag"));
  490. var etagAsString = etag.ToString();
  491. ushort version;
  492. var value = LoadJson(tableStorage.ScheduledReductions, etagAsString, writeBatch.Value, out version);
  493. if (value == null)
  494. continue;
  495. if (etag.CompareTo(currentEtag) > 0)
  496. {
  497. hasResult = true;
  498. result.Etag = etag;
  499. result.Timestamp = value.Value<DateTime>("timestamp");
  500. }
  501. var view = value.Value<int>("view");
  502. var level = value.Value<int>("level");
  503. var reduceKey = value.Value<string>("reduceKey");
  504. DeleteScheduledReduction(etagAsString, view, level, reduceKey);
  505. }
  506. return hasResult ? result : null;
  507. }
  508. public void DeleteScheduledReduction(int view, int level, string reduceKey)
  509. {
  510. var reduceKeyHash = HashKey(reduceKey);
  511. var scheduledReductionsByViewAndLevelAndReduceKey = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByViewAndLevelAndReduceKey);
  512. using (var iterator = scheduledReductionsByViewAndLevelAndReduceKey.MultiRead(Snapshot, CreateKey(view, level, reduceKey, reduceKeyHash)))
  513. {
  514. if (!iterator.Seek(Slice.BeforeAllKeys))
  515. return;
  516. do
  517. {
  518. var id = iterator.CurrentKey;
  519. DeleteScheduledReduction(id, view, level, reduceKey);
  520. }
  521. while (iterator.MoveNext());
  522. }
  523. }
  524. public void PutReducedResult(int view, string reduceKey, int level, int sourceBucket, int bucket, RavenJObject data)
  525. {
  526. var reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket =
  527. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndSourceBucket);
  528. var reduceResultsByViewAndReduceKeyAndLevelAndBucket =
  529. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndBucket);
  530. var reduceResultsByViewAndReduceKeyAndLevel =
  531. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevel);
  532. var reduceResultsByView =
  533. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByView);
  534. var reduceResultsData = tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.Data);
  535. var ms = CreateStream();
  536. using (
  537. var stream = documentCodecs.Aggregate((Stream) new UndisposableStream(ms),
  538. (ds, codec) => codec.Value.Encode(reduceKey, data, null, ds)))
  539. {
  540. data.WriteTo(stream);
  541. stream.Flush();
  542. }
  543. var id = generator.CreateSequentialUuid(UuidType.MappedResults);
  544. var idAsString = id.ToString();
  545. var reduceKeyHash = HashKey(reduceKey);
  546. tableStorage.ReduceResults.Add(
  547. writeBatch.Value,
  548. idAsString,
  549. new RavenJObject
  550. {
  551. { "view", view },
  552. { "etag", id.ToByteArray() },
  553. { "reduceKey", reduceKey },
  554. { "level", level },
  555. { "sourceBucket", sourceBucket },
  556. { "bucket", bucket },
  557. { "timestamp", SystemTime.UtcNow }
  558. },
  559. 0);
  560. ms.Position = 0;
  561. reduceResultsData.Add(writeBatch.Value, idAsString, ms, 0);
  562. var viewAndReduceKeyAndLevelAndSourceBucket = CreateKey(view, reduceKey, reduceKeyHash, level, sourceBucket);
  563. var viewAndReduceKeyAndLevel = CreateKey(view, reduceKey, reduceKeyHash, level);
  564. var viewAndReduceKeyAndLevelAndBucket = CreateKey(view, reduceKey, reduceKeyHash, level, bucket);
  565. reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket.MultiAdd(writeBatch.Value, viewAndReduceKeyAndLevelAndSourceBucket, idAsString);
  566. reduceResultsByViewAndReduceKeyAndLevel.MultiAdd(writeBatch.Value, viewAndReduceKeyAndLevel, idAsString);
  567. reduceResultsByViewAndReduceKeyAndLevelAndBucket.MultiAdd(writeBatch.Value, viewAndReduceKeyAndLevelAndBucket, idAsString);
  568. reduceResultsByView.MultiAdd(writeBatch.Value, CreateKey(view), idAsString);
  569. }
  570. public void RemoveReduceResults(int view, int level, string reduceKey, int sourceBucket)
  571. {
  572. var reduceKeyHash = HashKey(reduceKey);
  573. var viewAndReduceKeyAndLevelAndSourceBucket = CreateKey(view, reduceKey, reduceKeyHash, level, sourceBucket);
  574. var reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket =
  575. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndSourceBucket);
  576. using (var iterator = reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket.MultiRead(Snapshot, viewAndReduceKeyAndLevelAndSourceBucket))
  577. {
  578. if (!iterator.Seek(Slice.BeforeAllKeys))
  579. return;
  580. do
  581. {
  582. RemoveReduceResult(iterator.CurrentKey.Clone());
  583. }
  584. while (iterator.MoveNext());
  585. }
  586. }
  587. public IEnumerable<ReduceTypePerKey> GetReduceTypesPerKeys(int view, int take, int limitOfItemsToReduceInSingleStep)
  588. {
  589. if (take <= 0)
  590. take = 1;
  591. var allKeysToReduce = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
  592. var key = CreateKey(view);
  593. var scheduledReductionsByView = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByView);
  594. using (var iterator = scheduledReductionsByView.MultiRead(Snapshot, key))
  595. {
  596. if (!iterator.Seek(Slice.BeforeAllKeys))
  597. yield break;
  598. var processedItems = 0;
  599. do
  600. {
  601. ushort version;
  602. var value = LoadJson(tableStorage.ScheduledReductions, iterator.CurrentKey, writeBatch.Value, out version);
  603. allKeysToReduce.Add(value.Value<string>("reduceKey"));
  604. processedItems++;
  605. }
  606. while (iterator.MoveNext() && processedItems < take);
  607. }
  608. foreach (var reduceKey in allKeysToReduce)
  609. {
  610. var count = GetNumberOfMappedItemsPerReduceKey(view, reduceKey);
  611. var reduceType = count >= limitOfItemsToReduceInSingleStep ? ReduceType.MultiStep : ReduceType.SingleStep;
  612. yield return new ReduceTypePerKey(reduceKey, reduceType);
  613. }
  614. }
  615. private int GetNumberOfMappedItemsPerReduceKey(int view, string reduceKey)
  616. {
  617. var reduceKeyHash = HashKey(reduceKey);
  618. var key = CreateKey(view, reduceKey, reduceKeyHash);
  619. ushort version;
  620. var value = LoadJson(tableStorage.ReduceKeyCounts, key, writeBatch.Value, out version);
  621. if (value == null)
  622. return 0;
  623. return value.Value<int>("mappedItemsCount");
  624. }
  625. public void UpdatePerformedReduceType(int view, string reduceKey, ReduceType reduceType)
  626. {
  627. var reduceKeyHash = HashKey(reduceKey);
  628. var key = CreateKey(view, reduceKey, reduceKeyHash);
  629. var version = tableStorage.ReduceKeyTypes.ReadVersion(Snapshot, key);
  630. AddReduceKeyType(key, view, reduceKey, reduceType, version);
  631. }
  632. private void DeleteReduceKeyCount(string key, int view, ushort? expectedVersion)
  633. {
  634. var reduceKeyCountsByView = tableStorage.ReduceKeyCounts.GetIndex(Tables.ReduceKeyCounts.Indices.ByView);
  635. tableStorage.ReduceKeyCounts.Delete(writeBatch.Value, key, expectedVersion);
  636. reduceKeyCountsByView.MultiDelete(writeBatch.Value, CreateKey(view), key);
  637. }
  638. private void DeleteReduceKeyType(string key, int view, ushort? expectedVersion)
  639. {
  640. var reduceKeyTypesByView = tableStorage.ReduceKeyTypes.GetIndex(Tables.ReduceKeyTypes.Indices.ByView);
  641. tableStorage.ReduceKeyTypes.Delete(writeBatch.Value, key, expectedVersion);
  642. reduceKeyTypesByView.MultiDelete(writeBatch.Value, CreateKey(view), key);
  643. }
  644. private void AddReduceKeyCount(string key, int view, string reduceKey, int count, ushort? expectedVersion)
  645. {
  646. var reduceKeyCountsByView = tableStorage.ReduceKeyCounts.GetIndex(Tables.ReduceKeyCounts.Indices.ByView);
  647. tableStorage.ReduceKeyCounts.Add(
  648. writeBatch.Value,
  649. key,
  650. new RavenJObject
  651. {
  652. { "view", view },
  653. { "reduceKey", reduceKey },
  654. { "mappedItemsCount", count }
  655. }, expectedVersion);
  656. reduceKeyCountsByView.MultiAdd(writeBatch.Value, CreateKey(view), key);
  657. }
  658. private void AddReduceKeyType(string key, int view, string reduceKey, ReduceType status, ushort? expectedVersion)
  659. {
  660. var reduceKeyTypesByView = tableStorage.ReduceKeyTypes.GetIndex(Tables.ReduceKeyTypes.Indices.ByView);
  661. tableStorage.ReduceKeyTypes.Add(
  662. writeBatch.Value,
  663. key,
  664. new RavenJObject
  665. {
  666. { "view", view },
  667. { "reduceKey", reduceKey },
  668. { "reduceType", (int)status }
  669. }, expectedVersion);
  670. reduceKeyTypesByView.MultiAdd(writeBatch.Value, CreateKey(view), key);
  671. }
  672. public ReduceType GetLastPerformedReduceType(int view, string reduceKey)
  673. {
  674. var reduceKeyHash = HashKey(reduceKey);
  675. var key = CreateKey(view, reduceKey, reduceKeyHash);
  676. ushort version;
  677. var value = LoadJson(tableStorage.ReduceKeyTypes, key, writeBatch.Value, out version);
  678. if (value == null)
  679. return ReduceType.None;
  680. return (ReduceType)value.Value<int>("reduceType");
  681. }
  682. public IEnumerable<int> GetMappedBuckets(int view, string reduceKey)
  683. {
  684. var reduceKeyHash = HashKey(reduceKey);
  685. var viewAndReduceKey = CreateKey(view, reduceKey, reduceKeyHash);
  686. var mappedResultsByViewAndReduceKey = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKey);
  687. using (var iterator = mappedResultsByViewAndReduceKey.MultiRead(Snapshot, viewAndReduceKey))
  688. {
  689. if (!iterator.Seek(Slice.BeforeAllKeys))
  690. yield break;
  691. do
  692. {
  693. ushort version;
  694. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  695. yield return value.Value<int>("bucket");
  696. }
  697. while (iterator.MoveNext());
  698. }
  699. }
  700. public IEnumerable<MappedResultInfo> GetMappedResults(int view, IEnumerable<string> keysToReduce, bool loadData)
  701. {
  702. var mappedResultsByViewAndReduceKey = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKey);
  703. var mappedResultsData = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.Data);
  704. foreach (var reduceKey in keysToReduce)
  705. {
  706. var reduceKeyHash = HashKey(reduceKey);
  707. var viewAndReduceKey = CreateKey(view, reduceKey, reduceKeyHash);
  708. using (var iterator = mappedResultsByViewAndReduceKey.MultiRead(Snapshot, viewAndReduceKey))
  709. {
  710. if (!iterator.Seek(Slice.BeforeAllKeys))
  711. continue;
  712. do
  713. {
  714. ushort version;
  715. var value = LoadJson(tableStorage.MappedResults, iterator.CurrentKey, writeBatch.Value, out version);
  716. var size = tableStorage.MappedResults.GetDataSize(Snapshot, iterator.CurrentKey);
  717. yield return new MappedResultInfo
  718. {
  719. Bucket = value.Value<int>("bucket"),
  720. ReduceKey = value.Value<string>("reduceKey"),
  721. Etag = Etag.Parse(value.Value<byte[]>("etag")),
  722. Timestamp = value.Value<DateTime>("timestamp"),
  723. Data = loadData ? LoadMappedResult(iterator.CurrentKey, value, mappedResultsData) : null,
  724. Size = size
  725. };
  726. }
  727. while (iterator.MoveNext());
  728. }
  729. }
  730. }
  731. private RavenJObject LoadMappedResult(Slice key, RavenJObject value, Index dataIndex)
  732. {
  733. var reduceKey = value.Value<string>("reduceKey");
  734. var read = dataIndex.Read(Snapshot, key, writeBatch.Value);
  735. if (read == null)
  736. return null;
  737. using (var readerStream = read.Reader.AsStream())
  738. {
  739. using (var stream = documentCodecs.Aggregate(readerStream, (ds, codec) => codec.Decode(reduceKey, null, ds)))
  740. return stream.ToJObject();
  741. }
  742. }
  743. public IEnumerable<ReduceTypePerKey> GetReduceKeysAndTypes(int view, int start, int take)
  744. {
  745. var reduceKeyTypesByView = tableStorage.ReduceKeyTypes.GetIndex(Tables.ReduceKeyTypes.Indices.ByView);
  746. using (var iterator = reduceKeyTypesByView.MultiRead(Snapshot, CreateKey(view)))
  747. {
  748. if (!iterator.Seek(Slice.BeforeAllKeys) || !iterator.Skip(start))
  749. yield break;
  750. var count = 0;
  751. do
  752. {
  753. ushort version;
  754. var value = LoadJson(tableStorage.ReduceKeyTypes, iterator.CurrentKey, writeBatch.Value, out version);
  755. yield return new ReduceTypePerKey(value.Value<string>("reduceKey"), (ReduceType)value.Value<int>("reduceType"));
  756. count++;
  757. }
  758. while (iterator.MoveNext() && count < take);
  759. }
  760. }
  761. public void DeleteScheduledReductionForView(int view)
  762. {
  763. var scheduledReductionsByView = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByView);
  764. using (var iterator = scheduledReductionsByView.MultiRead(Snapshot, CreateKey(view)))
  765. {
  766. if (!iterator.Seek(Slice.BeforeAllKeys))
  767. return;
  768. do
  769. {
  770. var id = iterator.CurrentKey.Clone();
  771. ushort version;
  772. var value = LoadJson(tableStorage.ScheduledReductions, id, writeBatch.Value, out version);
  773. if (value == null)
  774. continue;
  775. var v = value.Value<int>("view");
  776. var level = value.Value<int>("level");
  777. var reduceKey = value.Value<string>("reduceKey");
  778. DeleteScheduledReduction(id, v, level, reduceKey);
  779. }
  780. while (iterator.MoveNext());
  781. }
  782. }
  783. public void RemoveReduceResultsForView(int view)
  784. {
  785. var reduceResultsByView =
  786. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByView);
  787. using (var iterator = reduceResultsByView.MultiRead(Snapshot, CreateKey(view)))
  788. {
  789. if (!iterator.Seek(Slice.BeforeAllKeys))
  790. return;
  791. do
  792. {
  793. var id = iterator.CurrentKey.Clone();
  794. RemoveReduceResult(id);
  795. }
  796. while (iterator.MoveNext());
  797. }
  798. }
  799. private void DeleteScheduledReduction(Slice id, int view, int level, string reduceKey)
  800. {
  801. var reduceKeyHash = HashKey(reduceKey);
  802. var scheduledReductionsByView = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByView);
  803. var scheduledReductionsByViewAndLevelAndReduceKey = tableStorage.ScheduledReductions.GetIndex(Tables.ScheduledReductions.Indices.ByViewAndLevelAndReduceKey);
  804. tableStorage.ScheduledReductions.Delete(writeBatch.Value, id);
  805. scheduledReductionsByView.MultiDelete(writeBatch.Value, CreateKey(view), id);
  806. scheduledReductionsByViewAndLevelAndReduceKey.MultiDelete(writeBatch.Value, CreateKey(view, level, reduceKey, reduceKeyHash), id);
  807. }
  808. private void DeleteMappedResult(Slice id, int view, string documentId, string reduceKey, string bucket)
  809. {
  810. var reduceKeyHash = HashKey(reduceKey);
  811. var viewAndDocumentId = CreateKey(view, documentId);
  812. var viewAndReduceKey = CreateKey(view, reduceKey, reduceKeyHash);
  813. var viewAndReduceKeyAndSourceBucket = CreateKey(view, reduceKey, reduceKeyHash, bucket);
  814. var mappedResultsByViewAndDocumentId = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndDocumentId);
  815. var mappedResultsByView = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByView);
  816. var mappedResultsByViewAndReduceKey = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKey);
  817. var mappedResultsByViewAndReduceKeyAndSourceBucket = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.ByViewAndReduceKeyAndSourceBucket);
  818. var mappedResultsData = tableStorage.MappedResults.GetIndex(Tables.MappedResults.Indices.Data);
  819. tableStorage.MappedResults.Delete(writeBatch.Value, id);
  820. mappedResultsByViewAndDocumentId.MultiDelete(writeBatch.Value, viewAndDocumentId, id);
  821. mappedResultsByView.MultiDelete(writeBatch.Value, CreateKey(view), id);
  822. mappedResultsByViewAndReduceKey.MultiDelete(writeBatch.Value, viewAndReduceKey, id);
  823. mappedResultsByViewAndReduceKeyAndSourceBucket.MultiDelete(writeBatch.Value, viewAndReduceKeyAndSourceBucket, id);
  824. mappedResultsData.Delete(writeBatch.Value, id);
  825. }
  826. private void RemoveReduceResult(Slice id)
  827. {
  828. ushort version;
  829. var value = LoadJson(tableStorage.ReduceResults, id, writeBatch.Value, out version);
  830. var view = value.Value<string>("view");
  831. var reduceKey = value.Value<string>("reduceKey");
  832. var level = value.Value<int>("level");
  833. var bucket = value.Value<int>("bucket");
  834. var sourceBucket = value.Value<int>("sourceBucket");
  835. var reduceKeyHash = HashKey(reduceKey);
  836. var viewAndReduceKeyAndLevelAndSourceBucket = CreateKey(view, reduceKey, reduceKeyHash, level, sourceBucket);
  837. var viewAndReduceKeyAndLevel = CreateKey(view, reduceKey, reduceKeyHash, level);
  838. var viewAndReduceKeyAndLevelAndBucket = CreateKey(view, reduceKey, reduceKeyHash, level, bucket);
  839. var reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket =
  840. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndSourceBucket);
  841. var reduceResultsByViewAndReduceKeyAndLevel =
  842. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevel);
  843. var reduceResultsByViewAndReduceKeyAndLevelAndBucket =
  844. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByViewAndReduceKeyAndLevelAndBucket);
  845. var reduceResultsByView =
  846. tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.ByView);
  847. var reduceResultsData = tableStorage.ReduceResults.GetIndex(Tables.ReduceResults.Indices.Data);
  848. tableStorage.ReduceResults.Delete(writeBatch.Value, id);
  849. reduceResultsByViewAndReduceKeyAndLevelAndSourceBucket.MultiDelete(writeBatch.Value, viewAndReduceKeyAndLevelAndSourceBucket, id);
  850. reduceResultsByViewAndReduceKeyAndLevel.MultiDelete(writeBatch.Value, viewAndReduceKeyAndLevel, id);
  851. reduceResultsByViewAndReduceKeyAndLevelAndBucket.MultiDelete(writeBatch.Value, viewAndReduceKeyAndLevelAndBucket, id);
  852. reduceResultsByView.MultiDelete(writeBatch.Value, CreateKey(view), id);
  853. reduceResultsData.Delete(writeBatch.Value, id);
  854. }
  855. private static string HashKey(string key)
  856. {
  857. return Convert.ToBase64String(Encryptor.Current.Hash.Compute16(Encoding.UTF8.GetBytes(key)));
  858. }
  859. }
  860. public class ScheduledReductionDeleter
  861. {
  862. private readonly ConcurrentSet<object> innerSet;
  863. private readonly IDictionary<Slice, object> state = new Dictionary<Slice, object>(new SliceEqualityComparer());
  864. public ScheduledReductionDeleter(ConcurrentSet<object> set, Func<object, Slice> extractKey)
  865. {
  866. innerSet = set;
  867. InitializeState(set, extractKey);
  868. }
  869. private void InitializeState(IEnumerable<object> set, Func<object, Slice> extractKey)
  870. {
  871. foreach (var item in set)
  872. {
  873. var key = extractKey(item);
  874. if (key == null)
  875. continue;
  876. state.Add(key, null);
  877. }
  878. }
  879. public bool Delete(Slice key, object value)
  880. {
  881. if (state.ContainsKey(key))
  882. return false;
  883. state.Add(key, null);
  884. innerSet.Add(value);
  885. return true;
  886. }
  887. }
  888. }