/// <summary> /// Initializes a new instance of the <see cref="ChunkSplit"/> class. /// </summary> /// <param name="start1">The first chunk's start marker.</param> /// <param name="end1">The first chunk's end marker.</param> /// <param name="start2">The second chunk's start marker.</param> /// <param name="end2">The second chunk's end marker.</param> public ChunkSplit(ChunkMarker start1, ChunkMarker end1, ChunkMarker start2, ChunkMarker end2) { _start1 = start1; _end1 = end1; _start2 = start2; _end2 = end2; }
/// <summary> /// Initializes a new instance of the <see cref="ChunkSplit"/> class. /// </summary> /// <param name="data">The data to read from.</param> /// <param name="index">The index at which to start reading from.</param> internal ChunkSplit(byte[] data, int index) { _start1 = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); _end1 = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); _start2 = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); _end2 = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); }
/// <summary> /// Initializes a new instance of the <see cref="ChunkTransfer"/> class. /// </summary> /// <param name="data">The data to read from.</param> /// <param name="index">The index at which to start reading from.</param> internal ChunkTransfer(byte[] data, int index) { string node = ByteArrayHelper.ToString(data, ref index); _node = new NodeDefinition(node.Split(':')[0], int.Parse(node.Split(':')[1])); _start = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); _end = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); }
/// <summary> /// Gets the chunk the specified id belongs in. /// </summary> /// <param name="id">The id to search for.</param> /// <returns>The chunk the specified id belongs in.</returns> private DatabaseChunk GetChunk(ObjectId id) { var value = _chunks.SingleOrDefault(e => ChunkMarker.IsBetween(e.Start, e.End, id.ToString())); if (value == null) { _lock.ExitReadLock(); throw new ChunkMovedException(); } return(value); }
/// <summary> /// Splits a chunk into two chunks. /// </summary> /// <returns>The new chunk created from the split.</returns> public DatabaseChunk Split() { var newData = new ConcurrentDictionary <ObjectId, Document>(_data.OrderBy(e => e.Key).Skip(_data.Count / 2).ToDictionary(e => e.Key, e => e.Value)); _data = new ConcurrentDictionary <ObjectId, Document>(_data.OrderBy(e => e.Key).Take(_data.Count / 2)); var oldEnd = _end; _end = new ChunkMarker(newData.Keys.Min().ToString()); return(new DatabaseChunk(_end, oldEnd, newData)); }
/// <summary> /// Initializes a new instance of the <see cref="ChunkListResponse"/> class. /// </summary> /// <param name="data">The data to read from.</param> /// <param name="index">The index at which to start reading from.</param> internal ChunkListResponse(byte[] data, int index) { _chunks = new List <ChunkDefinition>(); string s = ByteArrayHelper.ToString(data, ref index); string[] defs = s.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); foreach (var item in defs) { string[] def = item.Split(','); NodeDefinition nodeDef = new NodeDefinition(def[2].Split(':')[0], int.Parse(def[2].Split(':')[1])); _chunks.Add(new ChunkDefinition(ChunkMarker.ConvertFromString(def[0]), ChunkMarker.ConvertFromString(def[1]), nodeDef)); } }
/// <summary> /// Gets a list of the chunks from the internal document. /// </summary> /// <returns>A list of the chunks from the internal document.</returns> private List <ChunkDefinition> GetList() { List <ChunkDefinition> returnValue = new List <ChunkDefinition>(); for (int i = 0; i < _chunkList.Count; ++i) { var array = _chunkList[i.ToString()].ValueAsArray; var start = ChunkMarker.ConvertFromString(array[0].ValueAsString); var end = ChunkMarker.ConvertFromString(array[1].ValueAsString); var node = new NodeDefinition(array[2].ValueAsString.Split(':')[0], int.Parse(array[2].ValueAsString.Split(':')[1])); returnValue.Add(new ChunkDefinition(start, end, node)); } return(returnValue); }
/// <summary> /// Merges this chunk with the one passed in. /// </summary> /// <param name="c">The chunk to merge.</param> /// <remarks>Make sure the chunks are sequential and that the chunk passed in comes after the current chunk.</remarks> public void Merge(DatabaseChunk c) { if (!Equals(_end, c._start)) { throw new ArgumentException("The chunks are either not next to each other or you are trying to merge with the last chunk instead of the first."); } // Copy the data over. foreach (var item in c._data) { _data.TryAdd(item.Key, item.Value); } _end = c._end; }
/// <summary> /// Processes an update operation. /// </summary> /// <param name="dataOperation">The document that represents the operation.</param> /// <param name="message">The original message.</param> private void ProcessUpdateOperation(Document dataOperation, Message message) { UpdateOperation updateOperation = new UpdateOperation(dataOperation["update"].ValueAsDocument); if (!updateOperation.Valid) { SendMessage(new Message(message, updateOperation.ErrorMessage, false)); return; } _chunkListLock.EnterReadLock(); var chunk = _chunkList.SingleOrDefault(e => ChunkMarker.IsBetween(e.Start, e.End, updateOperation.DocumentId.ToString())); _chunkListLock.ExitReadLock(); NodeDefinition node = chunk == null ? null : chunk.Node; if (node == null) { SendMessage(new Message(message, new DataOperationResult(ErrorCodes.FailedMessage, "No storage node up for the specified id range."), false)); return; } Message operationMessage = new Message(node, message.Data, true); operationMessage.SetResponseCallback(delegate(Message originalOperationMessage) { if (originalOperationMessage.Success) { DataOperationResult result = (DataOperationResult)originalOperationMessage.Response.Data; Document resultDocument = new Document(result.Result); if (!resultDocument["success"].ValueAsBoolean && (ErrorCodes)Enum.Parse(typeof(ErrorCodes), resultDocument["errorcode"].ValueAsString) == ErrorCodes.ChunkMoved) { ProcessUpdateOperation(dataOperation, message); return; } SendMessage(new Message(message, result, false)); return; } SendMessage(new Message(message, new DataOperationResult(ErrorCodes.FailedMessage, "Failed to send message to storage node."), false)); }); SendMessage(operationMessage); }
/// <summary> /// Processes a <see cref="ChunkDataResponse"/> message. /// </summary> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> /// <param name="data">The data that is contained in that chunk.</param> public void ProcessChunkDataResponse(ChunkMarker start, ChunkMarker end, Document data) { Stopwatch timer = new Stopwatch(); timer.Start(); DatabaseChunk chunk = new DatabaseChunk(start, end); for (int i = 0; i < data["count"].ValueAsInteger; ++i) { var doc = data[i.ToString()].ValueAsDocument; chunk.TryAdd(new ObjectId(doc["id"].ValueAsString), doc); } timer.Stop(); _lock.EnterWriteLock(); _chunks.Add(chunk); _chunks.Sort(); _lock.ExitWriteLock(); Logger.Log("Chunk data added in " + timer.Elapsed.TotalSeconds + " seconds.", LogLevel.Info); }
/// <summary> /// Initializes a new instance of the <see cref="ChunkDataRequest"/> class. /// </summary> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> public ChunkDataRequest(ChunkMarker start, ChunkMarker end) { _start = start; _end = end; }
/// <summary> /// Initializes a new instance of the <see cref="DatabaseChunk"/> class. /// </summary> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> /// <param name="data">The data to load the chunk with.</param> private DatabaseChunk(ChunkMarker start, ChunkMarker end, ConcurrentDictionary <ObjectId, Document> data) { _start = start; _end = end; _data = data; }
/// <summary> /// Initializes a new instance of the <see cref="DatabaseChunk"/> class. /// </summary> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> public DatabaseChunk(ChunkMarker start, ChunkMarker end) { _start = start; _end = end; }
/// <summary> /// Initializes a new instance of the <see cref="ChunkTransfer"/> class. /// </summary> /// <param name="node">The node the chunk is on.</param> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> public ChunkTransfer(NodeDefinition node, ChunkMarker start, ChunkMarker end) { _node = node; _start = start; _end = end; }
/// <summary> /// Initializes a new instance of the <see cref="ChunkMerge"/> class. /// </summary> /// <param name="data">The data to read from.</param> /// <param name="index">The index at which to start reading from.</param> internal ChunkMerge(byte[] data, int index) { _start = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); _end = ChunkMarker.ConvertFromString(ByteArrayHelper.ToString(data, ref index)); }
/// <summary> /// Initializes a new instance of the <see cref="ChunkMerge"/> class. /// </summary> /// <param name="start">The chunk's start marker.</param> /// <param name="end">The chunk's end marker.</param> public ChunkMerge(ChunkMarker start, ChunkMarker end) { _start = start; _end = end; }
/// <summary> /// Initializes a new instance of the <see cref="ChunkDefinition"/> class. /// </summary> /// <param name="start">The start of the chunk.</param> /// <param name="end">The end of the chunk.</param> /// <param name="node">The node the chunk is on.</param> public ChunkDefinition(ChunkMarker start, ChunkMarker end, NodeDefinition node) { _start = start; _end = end; _node = node; }