Exemplo n.º 1
0
 private async Task _mergeRemoteBlockAsync(DiskViewModel diskModel, BlockOffset blockOffset, byte[] buffer)
 {
     using (var blockResp = await _serviceClient.GetAsync(new GetBlock()
         {
             DiskName = diskModel.Name,
             BlockOffset = blockOffset.Offset
         }))
     {
         // incorporate into the local disk
         blockResp.Read(buffer, 0, buffer.Length);
         diskModel.SynchronizingDisk.ReceiveChanges(blockOffset, buffer);
     }
 }
Exemplo n.º 2
0
 public bool CanSynchronize(DiskViewModel diskModel)
 {
     return diskModel != null && IsConnected && diskModel.SynchronizingDisk.ServerAssociation != null;
 }
Exemplo n.º 3
0
 private async Task _revertLocalChangesAsync(DiskViewModel diskModel, byte[] buffer)
 {
     var localLastSynchronized = diskModel.Disk.LastTimeSynchronized;
     var localChanges = diskModel.SynchronizingDisk.GetJournalEntriesSince(localLastSynchronized).ToArray();
     var blocksReverted = 0;
     foreach (var localChange in localChanges)
     {
         StatusText =
             string.Format("Detected conflict with disk {0} on server. Reverting local changes {1}/{2}",
                 diskModel.Name, blocksReverted, localChanges.Length);
         // Merge blocks from server according to local changes
         await _mergeRemoteBlockAsync(diskModel, localChange.BlockOffset, buffer);
         blocksReverted++;
     }
 }
Exemplo n.º 4
0
        private async Task _pushChangesToServerAsync(DiskViewModel diskModel)
        {
            // Mark this synchronization point, it needs to be included in the data uploaded to the server
            var localLastSynchronized = diskModel.Disk.LastTimeSynchronized;
            diskModel.SynchronizingDisk.NotifySynchronized();
            var localChanges = JournalEntry.ToJournalSet(diskModel.SynchronizingDisk.GetJournalEntriesSince(localLastSynchronized));

            // push to the server
            var blocksProcessed = 0;
            var buffer = new byte[diskModel.SynchronizingDisk.BlockSize];
            foreach (var localChange in localChanges)
            {
                StatusText =
                    string.Format("Pushing local changes to disk {0} to the server. {1}/{2} blocks uploaded.",
                        diskModel.Name, blocksProcessed, localChanges.Count);
                // read block from local disk into remporary buffer and then send it to the server
                diskModel.SynchronizingDisk.DirectRead(localChange.BlockOffset, buffer, 0);
                await _serviceClient.PutAsync(new PushBlock()
                    {
                        DiskName = diskModel.Name,
                        BlockOffset = localChange.BlockOffset.Offset,
                        Data = buffer
                    });
                blocksProcessed++;
            }
        }
Exemplo n.º 5
0
        private async Task _mergeRemoteBlocksAsync(DiskViewModel diskModel, IList<ChangeRecord> remoteChanges, byte[] buffer)
        {
            var blocksProcessed = 0;
            foreach (var remoteChange in remoteChanges)
            {
                StatusText = string.Format("Merging remote changes to disk {0} into local disk. {1}/{2} blocks merged",
                    diskModel.Name, blocksProcessed, remoteChanges.Count);

                await _mergeRemoteBlockAsync(diskModel, (BlockOffset) remoteChange.BlockOffset, buffer);

                blocksProcessed++;
            }
        }
Exemplo n.º 6
0
        public async void Synchronize(DiskViewModel diskModel)
        {
            StatusText = string.Format("Querying server about changes to disk {0}.", diskModel.Name);

            // Check when local disk and server were changed
            var localLastSynchronized = diskModel.Disk.LastTimeSynchronized;
            var changedBlockResponseTask =
                    _serviceClient.GetAsync(new ChangedBlocks
                        {
                            DiskName = diskModel.Name,
                            ChangesSince = localLastSynchronized
                        });
            var localHasChanges = !diskModel.SynchronizingDisk.GetJournalEntriesSince(localLastSynchronized)
                                    .IsEmpty();
            var remoteChanges = (await changedBlockResponseTask).Changes;
            var remoteHasChanges = remoteChanges.Count > 0;

            // Perform synchronization
            if (!remoteHasChanges && localHasChanges)
            {
                await _pushChangesToServerAsync(diskModel);
                StatusText = string.Format("Local changes to {0} successfully uploaded to the server.", diskModel.Name);
                await RefreshServerDisksAsync(suppressStatusMessage:true);
                diskModel.NotifyDiskChangedExternally();
            }
            else if(remoteHasChanges)
            {
                var buffer = new byte[diskModel.SynchronizingDisk.BlockSize];
                if (localHasChanges)
                {
                    // conflict --> revert local changes first
                    await _revertLocalChangesAsync(diskModel, buffer);
                }

                // merge remote changes into local disk
                await _mergeRemoteBlocksAsync(diskModel, remoteChanges, buffer);
                diskModel.NotifyDiskChangedExternally();

                StatusText = string.Format("Local disk {0} successfully updated with remote changes.", diskModel.Name);
            }
            else
            {
                StatusText = string.Format("No changes to be synchronized for disk {0}. Everything is up to date.", diskModel.Name);
            }
        }
Exemplo n.º 7
0
        public void RegisterDisk(string fileName, VirtualDisk vdisk, [NotNull] Dispatcher dispatcher)
        {
            if (fileName == null)
                throw new ArgumentNullException("fileName");
            if (vdisk == null)
                throw new ArgumentNullException("vdisk");
            if (dispatcher == null)
                throw new ArgumentNullException("dispatcher");
            
            var name = Path.GetFileNameWithoutExtension(fileName) ??
                "disk" + Interlocked.Increment(ref _uniqueDiskNameCounter);
            
            // have the virtual disk dispatch its notifications on the UI thread.
            Debug.Assert(dispatcher != null);
            vdisk.NotificationDispatcher = new WindowsDispatcherAdapter(dispatcher);

            var diskModel = new DiskViewModel
                {
                    Disk = vdisk,
                    Name = name,
                    FileName = fileName
                };
            OpenDisks.Add(diskModel);
        }
Exemplo n.º 8
0
        public async Task AssociateDiskAsync(DiskViewModel diskView)
        {
            DiskRecord resp;
            try
            {
                resp = await _serviceClient.GetAsync(new GetDiskInfo { DiskName = diskView.Name });
            }
            catch (WebServiceException e)
            {
                if (e.StatusCode == 404)
                {
                    resp = null;
                }
                else
                {
                    throw;
                }
            }

            var capacity = diskView.Disk.Capacity;
            diskView.SynchronizingDisk.ServerAssociation = diskView.Name;
            var oldNotificationDispatcher = diskView.Disk.NotificationDispatcher;

            if (resp == null)
            {
                // need to upload the disk first
                StatusText = String.Format("Disk {0} is being uploaded to the server. Please wait...", diskView.Name);
                try
                {
                    diskView.SynchronizingDisk.NotifySynchronized();
                    diskView.Disk.Dispose();
                    // ReSharper disable AssignNullToNotNullAttribute
                    diskView.Disk = null;
                    // ReSharper restore AssignNullToNotNullAttribute

                    using (var fs = new FileStream(diskView.FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
                    {
                        var request = new UploadDisk
                            {
                                Capacity = capacity,
                                DiskName = diskView.Name,
                                RequestStream = fs
                            };
                        var requestUrl = String.Format("{0}{1}?Capacity={2}", _serverUrl,
                            request.ToUrl("PUT").Substring(1), capacity);

                        //resp = await _serviceClient.PutAsync(request);
                        var req = WebRequest.CreateHttp(requestUrl);
                        req.Method = "PUT";
                        req.Accept = "application/json";

                        var reqStr = await req.GetRequestStreamAsync();
                        await fs.CopyToAsync(reqStr);
                        var rawResp = await req.GetResponseAsync();
                        var responseStream = rawResp.GetResponseStream();
                        if (responseStream != null)
                        {
                            using (var respReader = new StreamReader(responseStream, Encoding.UTF8))
                            {
                                var s = new JsonSerializer<DiskRecord>();
                                resp = s.DeserializeFromReader(respReader);
                            }
                        }
                        else
                        {
                            throw new InvalidOperationException("Missing response from upload.");
                        }

                        StatusText = string.Format("Disk {0} successfully uploaded to server.", diskView.Name);
                        await RefreshServerDisksAsync(suppressStatusMessage: true);
                    }
                }
                finally
                {
                    diskView.Disk = VirtualDisk.OpenExisting(diskView.FileName);
                    diskView.Disk.NotificationDispatcher = oldNotificationDispatcher;
                }
            }
            StatusText = String.Format("Disk {0} associated with server as {1}.", diskView.Name, resp.Name);
        }
Exemplo n.º 9
0
 public bool CanAssociateDisk(DiskViewModel diskView)
 {
     return diskView != null && IsConnected && diskView.SynchronizingDisk.ServerAssociation == null;
 }