Beispiel #1
0
        internal ReplicationFolder GetReplicationFolder(Guid storageID, string folderUrl)
        {
            if (storageID == Guid.Empty)
            {
                throw new ArgumentNullException("storageID");
            }

            if (string.IsNullOrEmpty(folderUrl))
            {
                throw new ArgumentNullException("folderUrl");
            }

            ReplicationFolder replicationFolder = null;

            if (_replicationFolders.ContainsKey(storageID))
            {
                Dictionary <string, ReplicationFolder> storageFolders = _replicationFolders[storageID];
                FolderUri uri = new FolderUri(folderUrl);
                if (storageFolders.ContainsKey(uri.UrlLower))
                {
                    replicationFolder = storageFolders[uri.UrlLower];
                }
            }

            return(replicationFolder);
        }
Beispiel #2
0
        private void StartFilesThread(ReplicationFolder replicationFolder)
        {
            if (replicationFolder == null || replicationFolder.SourceStorage == null)
            {
                throw new ArgumentNullException("storageNode");
            }

            //если это не текущий узел
            if (replicationFolder.SourceStorage.IsCurrent)
            {
                return;
            }

            string key = string.Format("{0}_{1}",
                                       replicationFolder.SourceStorage.UniqueID,
                                       replicationFolder.TypedFolder.ID);

            if (!_filesThread.ContainsKey(key))
            {
                lock (_addFilesThreadLocker)
                {
                    if (!_filesThread.ContainsKey(key))
                    {
                        Thread filesThread = new Thread(new ParameterizedThreadStart(this.FilesWorker));
                        filesThread.IsBackground = true;
                        _filesThread.Add(key, filesThread);
                        filesThread.Start(replicationFolder);
                    }
                }
            }
        }
        internal void ProcessRemoteFiles(ReplicationFolder replicationFolder, Tuple <Guid, Guid>[] remoteFiles)
        {
            if (replicationFolder == null)
            {
                throw new ArgumentNullException("replicationFolder");
            }

            //файлов может не быть
            if (remoteFiles == null || remoteFiles.Length == 0)
            {
                return;
            }

            var sourceStorage = replicationFolder.SourceStorage;

            if (sourceStorage.IsCurrent)
            {
                throw new Exception(string.Format("Невозможно реплицировать файлы с узла источника, который является текущим."));
            }

            //блокировка потоков обработки по папке репликации
            //в данный метод могут поступить ответы с 2х удаленных узлов
            //с пересекающейся коллекций файлов, поэтому лок по папке
            lock (this.GetFolderLock(replicationFolder.TypedFolder.ID))
            {
                this.ProcessRemoteFilesInternal(replicationFolder, remoteFiles);
            }
        }
Beispiel #4
0
        private ReplicationFolder GetReplicationFolder(ConfigReplicationFolder configReplicationFolder)
        {
            if (configReplicationFolder == null)
            {
                throw new ArgumentNullException("configReplicationFolder");
            }

            ReplicationFolder replicationFolder = null;

            IStorageMetadata replicationNodeMetadata = this.Engine.MetadataAdapter.GetStorage(configReplicationFolder.SourceNode);

            if (replicationNodeMetadata != null)
            {
                StorageNode replicationNode = this.GetStorage(replicationNodeMetadata.UniqueID);
                if (replicationNode == null)
                {
                    throw new Exception(string.Format("Невозможно найти узел репликации {0} для папки {1}",
                                                      configReplicationFolder.SourceNode,
                                                      configReplicationFolder.Url));
                }

                replicationFolder = this.GetReplicationFolder(replicationNode.UniqueID, configReplicationFolder.Url);
            }
            return(replicationFolder);
        }
        internal void Merge(ReplicationFolder replicationFolder)
        {
            if (replicationFolder == null)
            {
                throw new ArgumentNullException("replicationFolder");
            }

            this.TypedFolders.Add(replicationFolder.Folder.Url);
        }
        public ReplicationSchemaItem(ReplicationFolder replicationFolder)
        {
            if (replicationFolder == null)
            {
                throw new ArgumentNullException("replicationFolder");
            }

            this.ReplicationFolder = replicationFolder;
        }
Beispiel #7
0
        private void AddReplicationFolder(ReplicationFolder replicationFolder)
        {
            if (replicationFolder == null)
            {
                throw new ArgumentNullException("replicationFolder");
            }

            Dictionary <string, ReplicationFolder> nodeReplicationFolders = null;
            bool added = false;

            if (!_replicationFolders.ContainsKey(replicationFolder.SourceStorage.UniqueID))
            {
                lock (_checkReplicationFolderLocker)
                {
                    if (!_replicationFolders.ContainsKey(replicationFolder.SourceStorage.UniqueID))
                    {
                        nodeReplicationFolders = new Dictionary <string, ReplicationFolder>();
                        FolderUri uri = new FolderUri(replicationFolder.TypedFolder.Url);
                        nodeReplicationFolders.Add(uri.UrlLower, replicationFolder);
                        _replicationFolders.Add(replicationFolder.SourceStorage.UniqueID, nodeReplicationFolders);

                        //запускаем поток по репликации папки
                        this.StartFilesThread(replicationFolder);

                        added = true;
                    }
                }
            }

            if (!added)
            {
                //внутренний словарь должен был либо добавиться выше, либо уже существовать
                if (!_replicationFolders.ContainsKey(replicationFolder.SourceStorage.UniqueID))
                {
                    throw new Exception(string.Format("Не удалось добавить папку репликации, неизвестная ошибка."));
                }

                nodeReplicationFolders = _replicationFolders[replicationFolder.SourceStorage.UniqueID];
                FolderUri uri = new FolderUri(replicationFolder.TypedFolder.Url);
                if (!nodeReplicationFolders.ContainsKey(uri.UrlLower))
                {
                    lock (_checkReplicationFolderLocker)
                    {
                        if (!nodeReplicationFolders.ContainsKey(uri.UrlLower))
                        {
                            nodeReplicationFolders.Add(uri.UrlLower, replicationFolder);
                            this.StartFilesThread(replicationFolder);
                        }
                    }
                }
            }
        }
Beispiel #8
0
        private void BuildReplicationFolders()
        {
            //построение словаря папок репликации
            ICollection <IReplicationFolderMetadata> replicationFolders = this.Engine.MetadataAdapter.GetReplicationFolders();

            foreach (IReplicationFolderMetadata replicationFolderMetadata in replicationFolders)
            {
                StorageNode       storageNode       = new StorageNode(this.Engine, replicationFolderMetadata.SourceStorage);
                Folder            folder            = this.Engine.EnsureFolderInternal(replicationFolderMetadata.Folder.Url);
                ReplicationFolder replicationFolder = new ReplicationFolder(this.Engine, folder, storageNode, replicationFolderMetadata);
                this.AddReplicationFolder(replicationFolder);
            }
        }
Beispiel #9
0
        private void AddWeakRelation(Guid storageID, string host, string folderUrl)
        {
            if (string.IsNullOrEmpty(folderUrl))
            {
                throw new ArgumentNullException("folderUrl");
            }

            if (string.IsNullOrEmpty(host))
            {
                throw new ArgumentNullException("host");
            }

            bool exists = false;

            foreach (Dictionary <string, ReplicationFolder> storageReplicationFolders in _replicationFolders.Values)
            {
                FolderUri uri = new FolderUri(folderUrl);
                exists = storageReplicationFolders.ContainsKey(uri.UrlLower);
                if (exists)
                {
                    break;
                }
            }

            //настройка существует, но может существовать для другого узла
            //в таком случае нужно создать
            if (exists)
            {
                //но для текущего элемента схемы ее нет
                ReplicationFolder replicationFolder = this.GetReplicationFolder(storageID, folderUrl);
                lock (_updateFolderLocker)
                {
                    replicationFolder = this.GetReplicationFolder(storageID, folderUrl);
                    if (replicationFolder == null)
                    {
                        //создание узла для элемента схемы
                        bool        justCreated;
                        StorageNode schemaItemNode = this.EnsureNode(storageID, host, out justCreated);

                        bool replicationFolderJustCreated;
                        replicationFolder = this.EnsureReplicationFolder(schemaItemNode, folderUrl, false, out replicationFolderJustCreated);
                    }
                }
            }
        }
        /// <summary>
        /// Возвращает идентификаторы версий файлов для репликации.
        /// </summary>
        /// <param name="requestStorageID">Идентификатор узла, запрашивающего файлы для репликации.</param>
        /// <param name="folderUrl">Адрес папки.</param>
        /// <param name="from">Дата, с которой необходимо забрать файлы с узла источника.</param>
        /// <returns></returns>
        public Tuple <Guid, Guid>[] GetReplicationFiles(Guid requestStorageID, string folderUrl, DateTime @from)
        {
            if (requestStorageID == Guid.Empty)
            {
                throw new ArgumentNullException("requestStorageID");
            }

            if (string.IsNullOrEmpty(folderUrl))
            {
                throw new ArgumentNullException("folderUrl");
            }

            StorageNode requestStorage = this.ReplicationObserver.GetStorage(requestStorageID);

            if (requestStorage == null)
            {
                throw new Exception(string.Format("Не удалось найти узел хранилища с идентификатором {0}",
                                                  requestStorageID));
            }

            ReplicationFolder replicationFolder = this.ReplicationObserver.GetReplicationFolder(requestStorageID, folderUrl);

            if (replicationFolder == null)
            {
                throw new Exception(string.Format("Не удалось найти папку репликации с адресом {0} для узла {1}",
                                                  folderUrl,
                                                  requestStorage.Host));
            }

            Folder typedFolder = (Folder)replicationFolder.Folder;

            Tuple <Guid, Guid>[] files = this.Engine.MetadataAdapter.GetReplicationFiles(
                requestStorage.Metadata,
                typedFolder.Metadata,
                from);

            return(files);
        }
Beispiel #11
0
        private ReplicationFolder EnsureReplicationFolder(StorageNode sourceNode, string folderUrl, bool isCurrentSettings, out bool justCreated)
        {
            if (sourceNode == null)
            {
                throw new ArgumentNullException("sourceNode");
            }

            if (string.IsNullOrEmpty(folderUrl))
            {
                throw new ArgumentNullException("folderUrl");
            }

            justCreated = false;

            ReplicationFolder replicationFolder = this.GetReplicationFolder(sourceNode.UniqueID, folderUrl);

            if (replicationFolder == null)
            {
                lock (_ensureReplicationFolderLocker)
                {
                    replicationFolder = this.GetReplicationFolder(sourceNode.UniqueID, folderUrl);
                    if (replicationFolder == null)
                    {
                        Folder folder = this.Engine.EnsureFolderInternal(folderUrl);
                        IReplicationFolderMetadata replicationFolderMetadata = this.Engine.MetadataAdapter.CreateReplicationFolder(folder.Metadata, sourceNode.Metadata);
                        replicationFolderMetadata.IsCurrentNodeSettings = isCurrentSettings;
                        this.Engine.MetadataAdapter.SaveReplicationFolder(replicationFolderMetadata);
                        replicationFolder = new ReplicationFolder(this.Engine, folder, sourceNode, replicationFolderMetadata);

                        this.AddReplicationFolder(replicationFolder);
                    }
                }
            }

            return(replicationFolder);
        }
Beispiel #12
0
        private void FilesWorker(object state)
        {
            if (state == null)
            {
                throw new ArgumentNullException("state");
            }

            ReplicationFolder replicationFolder = (ReplicationFolder)state;

            while (true)
            {
                try
                {
                    //проверка необходимости дальнейшего продолжения реплицирования файлов
                    bool replicationExists = !replicationFolder.Deleted;
                    if (replicationExists)
                    {
                        Tuple <Guid, Guid>[] remoteFiles = this.ReplicationAdapter.Transport.GetReplicationFiles(
                            replicationFolder.SourceStorage,
                            this.Engine.CurrentNode.UniqueID,
                            replicationFolder.Folder.Url,
                            replicationFolder.LastSyncTime);

                        this.ReplicationAdapter.ProcessRemoteFiles(replicationFolder, remoteFiles);
                    }
                }
                catch (Exception ex)
                {
                    this.Engine.Logger.WriteMessage(ex.ToString());
                }
                finally
                {
                    Thread.Sleep(Timeouts.Files);
                }
            }
        }
Beispiel #13
0
        private void UpdateSchemaItem(IReplicationSchema remoteSchema, IReplicationSchemaItem remoteSchemaItem)
        {
            if (remoteSchema == null)
            {
                throw new ArgumentNullException("remoteSchema");
            }

            if (remoteSchemaItem == null)
            {
                throw new ArgumentNullException("remoteSchemaItem");
            }

            bool forCurrentStorage = remoteSchemaItem.StorageID == this.Engine.CurrentNode.UniqueID;
            bool isStrongRelation  = remoteSchemaItem.RelationType == ReplicationRelation.Strong;

            //хост хранилища может поменяться
            //ищем по UniqueID и если не совпадают хосты, то меняем хост
            //доверяем хосту, только от которого пришел ответ
            if (forCurrentStorage)
            {
                if (isStrongRelation)
                {
                    //есть строгая ссылка на текущий узел, для узла, с которого пришел запрос.
                    #region Обновление информации об узле
                    bool        justCreated;
                    StorageNode remoteNode = this.EnsureNode(remoteSchema.StorageID, remoteSchema.Host, out justCreated);

                    if (!justCreated)
                    {
                        //если узел уже был, то проверяем нужно ли обновить хост существующего узла
                        if (remoteNode.Host.ToLower() != remoteSchema.Host.ToLower())
                        {
                            lock (_updateStorageLocker)
                            {
                                if (remoteNode.Host.ToLower() != remoteSchema.Host.ToLower())
                                {
                                    remoteNode.Host = remoteSchema.Host.ToLower();
                                    remoteNode.Update();
                                }
                            }
                        }
                    }
                    #endregion
                }
            }

            //если это STRONG признак, то создаем, если настройки нет
            foreach (string folderUrl in remoteSchemaItem.Folders)
            {
                if (isStrongRelation)
                {
                    #region strong relation
                    //настройка пришла непосредственно с узла схемы и на этом узле есть
                    //если она предназначена для текущего узла, то создаем/снимаем признак удаленности
                    if (forCurrentStorage)
                    {
                        //узел remote схемы
                        bool        justCreated;
                        StorageNode remoteNode = this.EnsureNode(remoteSchema.StorageID, remoteSchema.Host, out justCreated);

                        //получаем папку для репликации с remote узлом
                        bool replicationFolderJustCreated;
                        ReplicationFolder replicationFolder = this.EnsureReplicationFolder(remoteNode, folderUrl, false, out replicationFolderJustCreated);
                        if (!replicationFolderJustCreated)
                        {
                            //если настройка существовала и была удалена, то восстанавливаем ее
                            if (replicationFolder.Deleted)
                            {
                                replicationFolder.Deleted = false;
                                replicationFolder.Update();
                            }
                        }
                    }
                    else
                    {
                        //Strong ссылка на репликацию с 3-им (отличным от текущего) узлом,
                        //смотрим если на текущем узле есть пересекающиеся папки, то добавляем weak настройку
                        this.AddWeakRelation(remoteSchemaItem.StorageID, remoteSchemaItem.Name, folderUrl);
                    }
                    #endregion
                }
                else
                {
                    if (forCurrentStorage)
                    {
                        //слабые ссылки на самого себя не надо восстанавливать
                        continue;
                    }

                    //если это WEAK признак, то создаем, только если есть пересекающиеся настройки
                    this.AddWeakRelation(remoteSchemaItem.StorageID, remoteSchemaItem.Name, folderUrl);

                    //проверку на признак удаления делать не нужно, т.к. ссылка слабая
                }
            }
        }
Beispiel #14
0
        internal void Init()
        {
            //Debugger.Launch();

            //1 - поднять настройку из бд
            this.BuildSettings();

            //2 - добавляем настройку из конфига в метаданные
            if (this.ReplicationConfiguration.ConfigFolders.Count > 0)
            {
                foreach (ConfigReplicationFolder configFolder in this.ReplicationConfiguration.ConfigFolders)
                {
                    //проверка существования настройки из конфига
                    ReplicationFolder replicationFolder = this.GetReplicationFolder(configFolder);
                    if (replicationFolder == null)
                    {
                        //папки репликации нет в метаданных, но есть в конфиге, нужно ее создать
                        StorageNode sourceStorage = null;
                        foreach (StorageNode node in _storageNodesByID.Values)
                        {
                            if (node.Host.ToLower() == configFolder.SourceNode.ToLower())
                            {
                                sourceStorage = node;
                                break;
                            }
                        }

                        if (sourceStorage == null)
                        {
                            //1 - нет самого узла источника данных
                            this.StartObserverThread(configFolder.SourceNode);
                        }
                        else
                        {
                            //2 - узел есть, создаем папку репликации
                            bool justCreated;
                            replicationFolder = this.EnsureReplicationFolder(sourceStorage, configFolder.Url, true, out justCreated);
                        }
                    }
                    else
                    {
                        bool updateRequired = false;
                        if (!replicationFolder.IsCurrentNodeSettings)
                        {
                            //если вдруг по каким-то причинам флаг сняли
                            replicationFolder.IsCurrentNodeSettings = true;
                            updateRequired = true;
                        }

                        if (replicationFolder.Deleted)
                        {
                            //восстановление настройки
                            replicationFolder.Deleted = false;
                            updateRequired            = true;
                        }

                        if (updateRequired)
                        {
                            replicationFolder.Update();
                        }
                    }
                }
            }

            //3 - проверяем настройку из бд, которая была текущей по конфигу
            //т.к. ее могли удалить
            foreach (Dictionary <string, ReplicationFolder> storageReplicationFolders in _replicationFolders.Values)
            {
                foreach (ReplicationFolder replicationFolder in storageReplicationFolders.Values)
                {
                    //проверяем только текущую настройку, остальная может быть актуальной на других узлах
                    if (replicationFolder.IsCurrentNodeSettings)
                    {
                        if (!this.ReplicationConfiguration.ContainsFolder(replicationFolder.Folder.Url))
                        {
                            //в конфиге нет настройки из бд
                            //помечаем ее в бд, как удаленную
                            replicationFolder.Deleted = true;
                            replicationFolder.Update();
                        }
                    }
                }
            }
        }
        private void ProcessRemoteFilesInternal(ReplicationFolder replicationFolder, Tuple <Guid, Guid>[] remoteFiles)
        {
            if (replicationFolder == null)
            {
                throw new ArgumentNullException("replicationFolder");
            }

            if (remoteFiles == null || remoteFiles.Length == 0)
            {
                throw new ArgumentNullException("remoteFiles");
            }

            //словарь существующих файлов.
            Dictionary <Guid, File> existsFiles = new Dictionary <Guid, File>();

            Dictionary <string, byte> uniqueFileVersions = new Dictionary <string, byte>();

            //формируем словарь существующих файлов и списков файлов,
            //которых не существует и которые необходимо реплицировать.
            List <RemoteFileInfo> filesToDownload = new List <RemoteFileInfo>();

            foreach (Tuple <Guid, Guid> fileVersionInfo in remoteFiles)
            {
                Guid fileID            = fileVersionInfo.Item1;
                Guid fileVersionID     = fileVersionInfo.Item2;
                bool fileVersionExists = false;

                string key = string.Format("{0}_{1}",
                                           fileID,
                                           fileVersionID);

                if (uniqueFileVersions.ContainsKey(key))
                {
                    continue;
                }

                uniqueFileVersions.Add(key, 0);

                File file = null;
                try
                {
                    file = this.Engine.GetFileInternal(replicationFolder.Folder.Url, fileID, null, false);
                }
                catch (Exception fileEx)
                {
                    //таблицы с файлов может не быть.
                    this.Logger.WriteMessage(fileEx.ToString(), LogLevel.Error);
                }

                if (file != null)
                {
                    fileVersionExists = file.VersionUniqueID == fileVersionID || file.GetVersion(fileVersionID, false) != null;

                    if (!existsFiles.ContainsKey(file.UniqueID))
                    {
                        existsFiles.Add(file.UniqueID, file);
                    }
                }

                if (!fileVersionExists)
                {
                    filesToDownload.Add(new RemoteFileInfo(fileVersionInfo, replicationFolder.Folder));
                }
            }

            if (filesToDownload.Count == 0)
            {
                return;
            }

            DateTime?lastSync = null;

            try
            {
                foreach (RemoteFileInfo remoteFileInfo in filesToDownload)
                {
                    IRemoteFile remoteFile = null;

                    try
                    {
                        remoteFile = this.Transport.GetReplicationFile(
                            replicationFolder.SourceStorage,
                            remoteFileInfo.Folder.Url,
                            remoteFileInfo.UniqueID,
                            remoteFileInfo.VersionID);

                        if (remoteFile == null)
                        {
                            throw new Exception(string.Format("Не удалось получить файла с идентификатором {0} с узла {1}",
                                                              remoteFileInfo.UniqueID,
                                                              replicationFolder.SourceStorage.Host));
                        }

                        StorageNode typedNode = (StorageNode)replicationFolder.SourceStorage;
                        remoteFile.CreatedStorageNode = typedNode.Metadata;

                        var stream = remoteFile.Stream;
                        if (stream == null)
                        {
                            throw new Exception(string.Format("Не удалось получить поток файла с идентификатором {0} с узла {1}",
                                                              remoteFileInfo.UniqueID,
                                                              replicationFolder.SourceStorage.Host));
                        }

                        File localFile = null;
                        if (existsFiles.ContainsKey(remoteFile.UniqueID))
                        {
                            localFile = existsFiles[remoteFile.UniqueID];
                        }

                        if (localFile == null)
                        {
                            //загружаем новый файл
                            IFileVersionMetadata fileVersion = this.Engine.DataAdapter.WriteRemoteFile(replicationFolder.TypedFolder.Metadata, remoteFile);
                            localFile = new File(this.Engine, replicationFolder.Folder, fileVersion.FileMetadata);

                            //добавляем в коллекцию существующих на текущем узле
                            existsFiles.Add(localFile.UniqueID, localFile);
                        }
                        else
                        {
                            //файл уже существует, добавляем только новую версию файла
                            this.Engine.DataAdapter.WriteRemoteFileVersion(localFile.Metadata, remoteFile);
                        }

                        //обновляем дату синхронизации по дате создания версии
                        lastSync = remoteFile.TimeCreated;
                    }
                    catch (Exception remoteFileEx)
                    {
                        throw new Exception(string.Format("Ошибка при репликации файла {0} с узла {1}",
                                                          remoteFileInfo.UniqueID,
                                                          replicationFolder.SourceStorage.Host), remoteFileEx);
                    }
                    finally
                    {
                        try
                        {
                            if (remoteFile != null && remoteFile.Stream != null)
                            {
                                remoteFile.Stream.Dispose();
                            }
                        }
                        catch (Exception innerEx)
                        {
                            this.Logger.WriteMessage(innerEx.ToString(), LogLevel.Error);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.Logger.WriteMessage(ex.ToString(), LogLevel.Error);
            }

            if (lastSync.HasValue)
            {
                replicationFolder.Metadata.LastSyncTime = lastSync.Value;
                replicationFolder.Update();
            }
        }