public static bool UpdateBubble(BubbleGroup group, VisualBubble[] bubbles, int searchDepth = 100) { //we can't operate if a thread/worker is concurrently processing a new bubble lock (OperationLock) { var groupDatabaseLocation = GetLocation(@group); var bubbleTuples = bubbles.Select(x => new Tuple<string, VisualBubble>(x.ID, x)).ToList(); VisualBubble lastBubble = null; long insertPosition = -1; using (var stream = File.Open(groupDatabaseLocation, FileMode.Open, FileAccess.ReadWrite)) { stream.Seek(stream.Length, SeekOrigin.Begin); for (var i = 0; i < (searchDepth != -1 ? searchDepth : Int32.MaxValue); i++) { if (stream.Position == 0) { break; } byte[] headerBytes; int headerBytesLength; int endPosition; BubbleGroupDatabasePrimitives.ReadBubbleHeader(stream, out headerBytes, out headerBytesLength); BubbleGroupDatabasePrimitives.FindBubbleHeaderDelimiter(headerBytes, headerBytesLength, 0, out endPosition); var bubbleDataLength = BubbleGroupDatabasePrimitives.JumpBubbleData(stream); //we need to seek over the data. var guid = BubbleGroupDatabasePrimitives.ReadBubbleHeaderStruct(headerBytes, headerBytesLength, endPosition + 1, out endPosition); Tuple<string, VisualBubble> bubbleTuple; if ((bubbleTuple = bubbleTuples.FirstOrDefault(x => x.Item1 == guid)) == null) { continue; } var b = bubbleTuple.Item2; var bubbleSize = headerBytesLength + bubbleDataLength + 8; var cutStart = stream.Position + bubbleSize; var cutLength = stream.Length - cutStart; insertPosition = stream.Position; using (var ms = new MemoryStream()) { Serializer.Serialize(ms, b); var updatedBubbleData = ms.ToArray(); var updatedBubbleHeader = b.GetType().Name + ":" + b.ID + ":" + b.Time; var updatedBubbleSize = updatedBubbleHeader.Length + updatedBubbleData.Length + 8; var bubbleInjectDelta = bubbleSize - updatedBubbleSize; //enough room if (bubbleInjectDelta != 0) { var injectPosition = stream.Position; stream.Position = cutStart; //higher var cut = new byte[cutLength]; stream.Read(cut, 0, (int)cutLength);//should always work as long as the count ain't crazy high //var bw = new BinaryWriter(stream, Encoding.ASCII); stream.Position = injectPosition; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, updatedBubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, updatedBubbleHeader); stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); } //they're the same! else if (bubbleInjectDelta == 0) { //var bw = new BinaryWriter(stream, Encoding.ASCII); BubbleGroupDatabasePrimitives.WriteBubbleData(stream, updatedBubbleData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, updatedBubbleHeader); } } if (cutLength == 0) { lastBubble = b; } bubbleTuples.Remove(bubbleTuple); if (!bubbleTuples.Any()) { break; } } BubbleGroupIndex.UpdateLastBubbleOrAndLastModifiedIndex(group.ID, lastBubble, insertPosition); } if (!bubbleTuples.Any()) { return true; } return false; } }
public static bool InsertBubblesByTime(BubbleGroup group, VisualBubble[] bubbles, int maxDepth = 1000, bool guidCheck = false, bool insertAtTop = false) { //we can't operate if a thread/worker is concurrently processing a new bubble lock (OperationLock) { var groupDatabaseLocation = GetLocation(@group); var bubbleTuples = bubbles.Select(x => new Tuple<long, VisualBubble>(x.Time, x)).ToList(); VisualBubble lastBubble = null; long insertPosition = -1; using (var stream = File.Open(groupDatabaseLocation, FileMode.Open, FileAccess.ReadWrite)) { stream.Seek(stream.Length, SeekOrigin.Begin); for (var i = 0; i < (maxDepth != -1 ? maxDepth : Int32.MaxValue); i++) { if (stream.Position == 0) { if (insertAtTop) { insertPosition = 0; var cut = new byte[(int)stream.Length]; stream.Read(cut, 0, (int)stream.Length); stream.Position = 0; var bubblesToInsert = bubbleTuples.Select(x => x.Item2).ToList(); bubblesToInsert.TimSort((x, y) => x.Time.CompareTo(y.Time)); foreach (var bubbleToInsert in bubblesToInsert) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, bubbleToInsert); var bubbleToInsertData = ms.ToArray(); var bubbleToInsertHeader = bubbleToInsert.GetType().Name + ":" + bubbleToInsert.ID + ":" + bubbleToInsert.Time; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleToInsertData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleToInsertHeader); } } stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); break; } else { break; } } byte[] headerBytes; int headerBytesLength; int endPosition; BubbleGroupDatabasePrimitives.ReadBubbleHeader(stream, out headerBytes, out headerBytesLength); BubbleGroupDatabasePrimitives.FindBubbleHeaderDelimiter(headerBytes, headerBytesLength, 0, out endPosition); var bubbleDataLength = BubbleGroupDatabasePrimitives.JumpBubbleData(stream); //we need to seek over the data. var guid = BubbleGroupDatabasePrimitives.ReadBubbleHeaderStruct(headerBytes, headerBytesLength, endPosition + 1, out endPosition); var time = BubbleGroupDatabasePrimitives.AsciiBytesToString(headerBytes, endPosition + 1, headerBytesLength); long longTime; Int64.TryParse(time, out longTime); { var bubblesToInsert = bubbleTuples.Where(x => { if (guidCheck && guid == x.Item2.ID) return false; if (longTime <= x.Item1) return true; return false; }).ToList(); if (!bubblesToInsert.Any()) { continue; } var bubbleSize = headerBytesLength + bubbleDataLength + 8; var insertLocation = stream.Position + bubbleSize; stream.Seek(insertLocation, SeekOrigin.Begin); var cutLength = stream.Length - insertLocation; var cut = new byte[cutLength]; stream.Read(cut, 0, (int)cutLength); //should always work as long as the count ain't crazy high stream.Seek(insertLocation, SeekOrigin.Begin); insertPosition = stream.Position; foreach (var bubbleToInsert in bubblesToInsert.Select(x => x.Item2)) { using (var ms = new MemoryStream()) { Serializer.Serialize(ms, bubbleToInsert); var bubbleToInsertData = ms.ToArray(); var bubbleToInsertHeader = bubbleToInsert.GetType().Name + ":" + bubbleToInsert.ID + ":" + bubbleToInsert.Time; BubbleGroupDatabasePrimitives.WriteBubbleData(stream, bubbleToInsertData); BubbleGroupDatabasePrimitives.WriteBubbleHeader(stream, bubbleToInsertHeader); } } stream.Write(cut, 0, cut.Length); stream.SetLength(stream.Position); // adding to end if (cut.Length == 0) { lastBubble = bubblesToInsert.Last().Item2; } foreach (var bubbleToInsert in bubblesToInsert) { bubbleTuples.Remove(bubbleToInsert); } if (!bubbleTuples.Any()) { break; } } } BubbleGroupIndex.UpdateLastBubbleOrAndLastModifiedIndex(group.ID, lastBubble, insertPosition); } if (!bubbleTuples.Any()) { return true; } return false; } }