private void StartRelationThread(StorageNode storageNode) { if (storageNode == null) { throw new ArgumentNullException("storageNode"); } //если это не текущий узел if (storageNode.IsCurrent) { return; } if (!_relationThread.ContainsKey(storageNode.UniqueID)) { lock (_commonLocker) { if (!_relationThread.ContainsKey(storageNode.UniqueID)) { Thread relationThread = new Thread(new ParameterizedThreadStart(this.GetNeighborsWorker)); relationThread.IsBackground = true; _relationThread.Add(storageNode.UniqueID, relationThread); relationThread.Start(storageNode); } } } }
private void AddStorageNode(StorageNode storageNode) { if (storageNode == null) { throw new ArgumentNullException("storageNode"); } if (!_storageNodesByID.ContainsKey(storageNode.UniqueID)) { lock (_addStorageLocker) { if (!_storageNodesByID.ContainsKey(storageNode.UniqueID)) { _storageNodesByID.Add(storageNode.UniqueID, storageNode); //после добавления узла, запускаем по нему поток с запросом //если это не текущий узел if (!storageNode.IsCurrent) { this.StartRelationThread(storageNode); } } } } }
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); }
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); } }
private void BuildSettings() { //построение словаря узлов файловых хранилищ. ICollection <IStorageMetadata> storageNodes = this.Engine.MetadataAdapter.GetStorages(); foreach (IStorageMetadata nodeMetadata in storageNodes) { StorageNode typedNode = new StorageNode(this.Engine, nodeMetadata); this.AddStorageNode(typedNode); } this.BuildReplicationFolders(); }
internal StorageNode GetStorage(Guid uniqueID) { if (uniqueID == Guid.Empty) { throw new ArgumentNullException("uniqueID"); } StorageNode node = null; if (_storageNodesByID.ContainsKey(uniqueID)) { node = _storageNodesByID[uniqueID]; } return(node); }
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); } } } }
private void RebuildStorageReplicationFolders(StorageNode node) { if (node == null) { throw new ArgumentNullException("node"); } //посмотреть конфиг и попытаться создать то, что еще не создано в бд foreach (ConfigReplicationFolder configFolder in this.ReplicationConfiguration.ConfigFolders) { //только для данного узла if (node.Host.ToLower() == configFolder.SourceNode.ToLower()) { //создаем папку репликации, если ее еще нет. bool justCreated; this.EnsureReplicationFolder(node, configFolder.Url, true, out justCreated); } } }
/// <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); }
private void GetNeighborsWorker(object state) { if (state == null) { throw new ArgumentNullException("state"); } StorageNode node = (StorageNode)state; while (true) { try { //периодически запрашиваем информацию о сети //передаем текущие папки, которые реплицируются на данной ноде //чтобы возвращать только пересекающиеся IReplicationSchema currentSchema = this.GetCurrentSchema(); IReplicationSchema remoteSchema = this.ReplicationAdapter.Transport.ExchangeSchema(node, currentSchema); //обновляем схему по схеме соседнего узла по следующей логике //что пришло со строгой ссылкой, то всегда создаем (значит эта настройка соседнего узла) //со слабой ссылкой создаем только папки, по которым мы пересекаемся if (remoteSchema != null) { this.UpdateSchema(remoteSchema); } } catch (Exception ex) { this.Engine.Logger.WriteMessage(ex.ToString()); } finally { Thread.Sleep(Timeouts.Schema); } } }
private StorageNode EnsureNode(Guid uniqueID, string host, out bool justCreated) { if (uniqueID == Guid.Empty) { throw new ArgumentNullException("uniqueID"); } justCreated = false; StorageNode savedNode = this.GetStorage(uniqueID); if (savedNode == null) { lock (_updateStorageLocker) { savedNode = this.GetStorage(uniqueID); if (savedNode == null) { //ноды нет в словаре, создаем IStorageMetadata nodeMetadata = this.Engine.MetadataAdapter.CreateStorageNode(host, uniqueID); nodeMetadata.LastAccessTime = DateTime.Now; savedNode = new StorageNode(this.Engine, nodeMetadata); this.Engine.MetadataAdapter.SaveStorage(nodeMetadata); //добавляем в словарь this.AddStorageNode(savedNode); justCreated = true; //после сохранения узла, может стать доступна настройка //репликации с тим узлом this.RebuildStorageReplicationFolders(savedNode); } } } return(savedNode); }
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); }
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); //проверку на признак удаления делать не нужно, т.к. ссылка слабая } } }
/// <summary> /// Обновляет текущую схему репликацию сети, по схеме репликации другого узла сети. /// </summary> /// <param name="remoteSchema">Схема репликации другого узла сети.</param> internal void UpdateSchema(IReplicationSchema remoteSchema) { if (remoteSchema == null) { throw new ArgumentNullException("remoteSchema"); } //remote схема содержит ссылки на текущий узел bool remoteSchemaContainsCurrentStorage = false; //обновляем схему по схеме соседнего узла по следующей логике //что пришло со строгой ссылкой, то всегда создаем (значит эта настройка соседнего узла) //со слабой ссылкой создаем только папки, по которым мы пересекаемся if (remoteSchema.StrongItems != null) { foreach (IReplicationSchemaItem schemaItem in remoteSchema.StrongItems) { bool forCurrentStorage = schemaItem.StorageID == this.Engine.CurrentNode.UniqueID; if (!remoteSchemaContainsCurrentStorage) { remoteSchemaContainsCurrentStorage = forCurrentStorage; } this.UpdateSchemaItem(remoteSchema, schemaItem); } } if (remoteSchema.WeakItems != null) { foreach (IReplicationSchemaItem schemaItem in remoteSchema.WeakItems) { bool forCurrentStorage = schemaItem.StorageID == this.Engine.CurrentNode.UniqueID; if (!remoteSchemaContainsCurrentStorage) { remoteSchemaContainsCurrentStorage = forCurrentStorage; } this.UpdateSchemaItem(remoteSchema, schemaItem); } } if (remoteSchemaContainsCurrentStorage) { //схема remote узла содержит текущий узел bool justCreated; StorageNode remoteNode = this.EnsureNode(remoteSchema.StorageID, remoteSchema.Host, out justCreated); remoteNode.LastAccessTime = DateTime.Now; remoteNode.Update(); } //удаление текущий настроек по remote схеме //для этого нужно пройтись по всем настройкам схемы текущего узла для remote узла if (_replicationFolders.ContainsKey(remoteSchema.StorageID)) { #region Удаление из текущей схемы Dictionary <string, ReplicationFolder> replicationFoldersForRemoteSchema = _replicationFolders[remoteSchema.StorageID]; foreach (ReplicationFolder replicationFolder in replicationFoldersForRemoteSchema.Values) { if (replicationFolder.IsCurrentNodeSettings) { //в схеме текущего узла репликация с remote узлом задана в настройке (STRONG) //такие настройки удалять не нужно continue; } bool containsInRemoteSchema = false; FolderUri localUri = new FolderUri(replicationFolder.Folder.Url); //содержаться может и в STRONG и в WEAK виде if (remoteSchema.StrongItems != null) { foreach (IReplicationSchemaItem schemaItem in remoteSchema.StrongItems) { if (schemaItem.Folders != null) { foreach (string folderUrl in schemaItem.Folders) { FolderUri remoteUri = new FolderUri(folderUrl); if (localUri.UrlLower == remoteUri.UrlLower) { containsInRemoteSchema = true; break; } } } if (containsInRemoteSchema) { break; } } } if (!containsInRemoteSchema && remoteSchema.WeakItems != null) { foreach (IReplicationSchemaItem schemaItem in remoteSchema.WeakItems) { if (schemaItem.Folders != null) { foreach (string folderUrl in schemaItem.Folders) { FolderUri remoteUri = new FolderUri(folderUrl); if (localUri.UrlLower == remoteUri.UrlLower) { containsInRemoteSchema = true; break; } } } if (containsInRemoteSchema) { break; } } } //в remote схеме нет репликации с папками из схемы текущего узла if (!containsInRemoteSchema) { replicationFolder.Deleted = true; replicationFolder.Update(); } } #endregion } }
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(); } }