private static void CmdAppend(string[] args) { if (args.Length != 1 && args.Length != 2) { Console.WriteLine("Usage: append <stream> <local>?"); Console.WriteLine("Appends events to a stream, discarding sequence ids."); return; } // The stream from which to append IReadOnlyList <EventData> from; if (args.Length == 1) { if (Current == null) { Console.WriteLine("No current stream available."); return; } from = Current; } else { if (!Fetched.TryGetValue(args[1], out from)) { Console.WriteLine("Stream '{0}' does not exist.", args[1]); return; } } // The stream to which to append var into = args[0]; var dstDriver = new StorageConfiguration(Parse(into)).Connect(); using (Release(dstDriver)) { var dst = new MigrationStream <JObject>(dstDriver); var sw = Stopwatch.StartNew(); var events = 0; Task.Run((Func <Task>)(async() => { Status("Current destination seq: ..."); var bakSeq = await dstDriver.GetLastKeyAsync(); Console.WriteLine("Current destination seq: {0}", bakSeq); ++bakSeq; while (events < @from.Count) { Status("Appending: {0}/{1}", events, @from.Count); var list = new List <KeyValuePair <uint, JObject> >(); for (var i = 0; i < 1000 && events < @from.Count; ++i, ++events, ++bakSeq) { list.Add(new KeyValuePair <uint, JObject>(bakSeq, @from[events].Event)); } events += list.Count; await dst.WriteAsync(list); } })).Wait(); Console.WriteLine("Appended {0} events in {1:F2}s.", events, sw.ElapsedMilliseconds / 1000.0); } }
/// <summary> Copies from source to destination, returns last position in source. </summary> private static long BackupCopy(string srcname, string dstname, uint maxseq) { var srcDriver = new StorageConfiguration(Parse(srcname)) { ReadOnly = true }.Connect(); using (Release(srcDriver)) { var dstDriver = new StorageConfiguration(Parse(dstname)).Connect(); using (Release(dstDriver)) { var src = new EventStream <JObject>(srcDriver); var dst = new MigrationStream <JObject>(dstDriver); var sw = Stopwatch.StartNew(); var events = 0; var initial = 0L; Status("Connecting..."); Task.Run((Func <Task>)(async() => { Status("Current source size: ..."); var maxPos = await srcDriver.GetPositionAsync(); Console.WriteLine("Current source size: {0:F2} MB", maxPos / (1024.0 * 1024.0)); Status("Current source seq: ..."); var maxSeq = await srcDriver.GetLastKeyAsync(); Console.WriteLine("Current source seq: {0}", maxSeq); Status("Current destination seq: ..."); var bakSeq = await dstDriver.GetLastKeyAsync(); Console.WriteLine("Current destination seq: {0}", bakSeq); if (bakSeq >= maxSeq) { Console.WriteLine("Destination already up-to-date."); return; } var asAzure = ((ReadOnlyDriverWrapper)srcDriver).Wrapped as AzureStorageDriver; if (asAzure != null) { for (var i = 0; i < asAzure.Blobs.Count; ++i) { Console.WriteLine("Blob {0}: {1:F2} MB from seq {2}", asAzure.Blobs[i].Name, asAzure.Blobs[i].Properties.Length / (1024.0 * 1024.0), i < asAzure.FirstKey.Count ? asAzure.FirstKey[i] : maxSeq); } } if (bakSeq > 0) { Status("Skipping to seq {0}...", bakSeq); await src.DiscardUpTo(bakSeq + 1); Console.WriteLine("Skipping to seq {0} done !", bakSeq); } initial = src.Position; Func <bool> more; do { var fetch = src.BackgroundFetchAsync(); var list = new List <KeyValuePair <uint, JObject> >(); JObject obj; while ((obj = src.TryGetNext()) != null) { list.Add(new KeyValuePair <uint, JObject>(src.Sequence, obj)); } events += list.Count; while (list.Count > 0 && list[list.Count - 1].Key > maxseq) { list.RemoveAt(list.Count - 1); } await dst.WriteAsync(list); Status("{0}/{1} ({2:F2}/{3:F2} MB)", src.Sequence, maxSeq, src.Position / (1024.0 * 1024.0), maxPos / (1024.0 * 1024.0)); more = await fetch; } while (more()); })).Wait(); Console.WriteLine("{0} events ({1:F2} MB) in {2:F2}s.", events, (src.Position - initial) / (1024.0 * 1024.0), sw.ElapsedMilliseconds / 1000.0); return(src.Position); } } }