コード例 #1
0
        public IFileVersionMetadata WriteRemoteFile(IFolderMetadata folderMetadata, IRemoteFile remoteFile)
        {
            if (folderMetadata == null)
            {
                throw new ArgumentNullException("folderMetadata");
            }

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

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

            if (remoteFile.Stream == null)
            {
                throw new ArgumentNullException("remoteFile.Stream");
            }

            IBlobFileMetadata blobFileMetadata = this.BlobMetadataAdapter.CreateFile(folderMetadata, remoteFile.Name);

            blobFileMetadata.Name = remoteFile.Name;

            //резервация параметров сохранения файла с
            blobFileMetadata.EnsureRemoteSaveProperties(remoteFile);

            //запись файла
            IFileVersionMetadata savedVersion = this.WriteInternal(blobFileMetadata, remoteFile.Stream, remoteFile.TimeCreated);

            return(savedVersion);
        }
コード例 #2
0
        public IBlobFileVersionMetadata SaveFile(IBlobFileMetadata fileMetadata, DateTime versionTimeCreated)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

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

            FileMetadata typedFile = (FileMetadata)fileMetadata;

            if (typedFile.ID != 0 && typedFile.RemoteFile == null)
            {
                if (typedFile.OriginalVersionUniqueID == Guid.Empty || fileMetadata.VersionUniqueID == typedFile.OriginalVersionUniqueID)
                {
                    throw new Exception("Для обновления существующего файла необходимо вызвать резервирование параметров сохранения.");
                }
            }

            this.Logger.WriteMessage("SaveFile: Начало.");

            FileVersionMetadata version = this.FileAdapter.UpdateFile(typedFile, versionTimeCreated);

            this.Logger.WriteMessage("SaveFile: Конец.");

            return(version);
        }
コード例 #3
0
        /// <summary>
        /// Записывает версию файла в хранилище.
        /// </summary>
        /// <param name="fileMetadata">Метаданные существующего файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <param name="fileName">Имя файла.</param>
        /// <returns></returns>
        public IFileVersionMetadata WriteFileVersion(IFileMetadata fileMetadata, Stream stream, string fileName = null)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.FolderMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata.FolderMetadata");
            }

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

            this.Logger.WriteFormatMessage("WriteFileVersion:Начало записи новой версии файла, fileMetadata.Name: {0}, fileMetadata.UniqueID: {1}", fileMetadata.Name, fileMetadata.UniqueID);

            IBlobFileMetadata blobFileMetadata = (IBlobFileMetadata)fileMetadata;

            if (!string.IsNullOrEmpty(fileName))
            {
                blobFileMetadata.Name = fileName;
            }

            //резервация параметров сохранения
            //например идентификатора версии, его нужно знать заранее.
            blobFileMetadata.EnsureSaveProperties();

            //запись версии файла
            IFileVersionMetadata savedVersion = this.WriteInternal(blobFileMetadata, stream);

            return(savedVersion);
        }
コード例 #4
0
        private void SerializeHeader(MemoryStream fileHeaderStream, IBlobFileMetadata fileMetadata, long contentLength, DateTime versionTimeCreated)
        {
            if (fileHeaderStream == null)
            {
                throw new ArgumentNullException("fileHeaderStream");
            }

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

            //текущая версия заголовка = BlobConsts.BlobFile.FileHeaderCurrentVersion
            JsonBlobFileHeaderV1 header = new JsonBlobFileHeaderV1()
            {
                ContentAbsoluteStartPosition = this.BlobStream.Position,
                ContentLength   = contentLength,
                FileName        = fileMetadata.Name,
                FolderUrl       = fileMetadata.FolderMetadata.Url,
                UniqueID        = fileMetadata.UniqueID,
                TimeCreated     = versionTimeCreated,
                VersionUniqueID = fileMetadata.VersionUniqueID,
            };

            JsonDataSerializer.Serialize(fileHeaderStream, header);
        }
コード例 #5
0
        /// <summary>
        /// Удаляет файл.
        /// </summary>
        /// <param name="folderUrl">Адрес папки.</param>
        /// <param name="fileUniqueID">Уникальный идентификатор файла.</param>
        /// <returns></returns>
        public bool DeleteFile(IFolderMetadata folderMetadata, Guid fileUniqueID)
        {
            if (folderMetadata == null)
            {
                throw new ArgumentNullException("folderMetadata");
            }

            if (fileUniqueID == Guid.Empty)
            {
                throw new ArgumentNullException("fileUniqueID");
            }

            this.Logger.WriteFormatMessage("DeleteFile:Начало удаления файла, folder.Url: {0}, file.UniqueID: {1}", folderMetadata.Url, fileUniqueID);

            bool result = false;
            //физического удаления для файла в блобе не предусмотрено
            //удаление заключается в установке Deleted для метаданных файла.
            IBlobFileMetadata fileMetadata = this.BlobMetadataAdapter.GetFile(folderMetadata, fileUniqueID);

            if (fileMetadata != null)
            {
                this.BlobMetadataAdapter.DeleteFile(fileMetadata);
                result = fileMetadata.Deleted;
            }
            this.Logger.WriteFormatMessage("DeleteFile:Окончание удаления файла, folder.Url: {0}, file.UniqueID: {1}", folderMetadata.Url, fileUniqueID);


            return(result);
        }
コード例 #6
0
        /// <summary>
        /// Записывает файл в хранилище.
        /// </summary>
        /// <param name="folderMetadata">Метаданные папки.</param>
        /// <param name="fileName">Имя файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <returns></returns>
        public IFileVersionMetadata WriteFile(IFolderMetadata folderMetadata, string fileName, Stream stream)
        {
            if (folderMetadata == null)
            {
                throw new ArgumentNullException("folderMetadata");
            }

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

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

            IBlobFileMetadata blobFileMetadata = this.BlobMetadataAdapter.CreateFile(folderMetadata, fileName);

            blobFileMetadata.Name = fileName;

            //запись файла
            IFileVersionMetadata savedVersion = this.WriteInternal(blobFileMetadata, stream);

            return(savedVersion);
        }
コード例 #7
0
        private void EnsureMetadata(IBlobMetadata blobMetadata, IFileHeader fileHeader, long fileAbsoluteStartPosition, long fileAbsoluteEndPosition)
        {
            if (blobMetadata == null)
            {
                throw new ArgumentNullException("blobMetadata");
            }

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

            if (fileAbsoluteStartPosition < 0)
            {
                throw new ArgumentNullException("fileAbsolutePosition");
            }

            if (fileAbsoluteEndPosition < 0)
            {
                throw new ArgumentNullException("fileAbsoluteEndPosition");
            }

            if (fileAbsoluteStartPosition >= fileAbsoluteEndPosition)
            {
                throw new Exception("fileAbsoluteStartPosition не может быть больше fileAbsoluteEndPosition");
            }

            IFolderMetadata   folderMetadata   = this.DataAdapter.MetadataAdapter.EnsureFolder(fileHeader.FolderUrl);
            IBlobFileMetadata blobFileMetadata = this.DataAdapter.BlobMetadataAdapter.GetFile(folderMetadata, fileHeader.UniqueID);

            if (blobFileMetadata != null)
            {
                //файл есть, проверяем текущую версию, есть ли она
                ICollection <IBlobFileVersionMetadata> versions = this.DataAdapter.BlobMetadataAdapter.GetVersions(blobFileMetadata);
                bool versionExists = false;
                if (versions != null)
                {
                    foreach (IBlobFileVersionMetadata version in versions)
                    {
                        if (version.UniqueID == fileHeader.VersionUniqueID)
                        {
                            versionExists = true;
                            break;
                        }
                    }
                }

                if (!versionExists)
                {
                    this.DataAdapter.BlobMetadataAdapter.AddExistsFileVersion(this.DataAdapter.MetadataAdapter.CurrentStorage, blobMetadata, folderMetadata, fileHeader, fileAbsoluteStartPosition, fileAbsoluteEndPosition);
                }
            }
            else
            {
                //файла нет, создаем метаданные файла
                this.DataAdapter.BlobMetadataAdapter.AddExistsFileVersion(this.DataAdapter.MetadataAdapter.CurrentStorage, blobMetadata, folderMetadata, fileHeader, fileAbsoluteStartPosition, fileAbsoluteEndPosition);
            }
        }
コード例 #8
0
ファイル: Blob.cs プロジェクト: soroush01110011/MVP
        /// <summary>
        /// Записывает содержимое файла в блоб.
        /// </summary>
        /// <param name="fileMetadata">Матаданные файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <param name="remoteTimeCreated">Время создания версии с удаленного узла.</param>
        /// <returns></returns>
        internal BlobFileInfo Write(IBlobFileMetadata fileMetadata, Stream stream, DateTime?remoteTimeCreated = null)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

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

            this.Container.DataAdapter.Logger.WriteFormatMessage("Blob.Write:Начало записи содержимого в блоб, file.UniqueID: {0}", fileMetadata.UniqueID);

            BlobFileInfo blobFileInfo = new BlobFileInfo();

            blobFileInfo.BlobID = this.ID;
            bool closeBlob = false;

            DateTime timeCreated;

            if (remoteTimeCreated.HasValue)
            {
                timeCreated = remoteTimeCreated.Value;
            }
            else
            {
                //начиная с 4ой версии хранится время в UTC
                timeCreated = DateTime.Now.ToUniversalTime();
            }

            using (FileStream fs = this.File.Open(FileMode.Append, FileAccess.Write, FileShare.Read))
            {
                BlobStreamAdapter streamAdapter = new BlobStreamAdapter(fs);
                blobFileInfo.BlobStartPosition = fs.Length;
                streamAdapter.Write(fileMetadata, stream, timeCreated);
                blobFileInfo.BlobEndPosition = fs.Length;
                blobFileInfo.TimeCreated     = timeCreated;

                closeBlob = fs.Length > this.Container.DataAdapter.MaxBlobSize;
            }

            if (closeBlob)
            {
                this.Metadata.Closed = true;
                this.Container.DataAdapter.BlobMetadataAdapter.SaveBlob(this.Metadata);
            }

            this.Container.DataAdapter.Logger.WriteFormatMessage("Blob.Write:Окончание записи содержимого в блоб, file.UniqueID: {0}. Блоб был закрыт после записи файла: {1}",
                                                                 fileMetadata.UniqueID,
                                                                 closeBlob);

            return(blobFileInfo);
        }
コード例 #9
0
        public void DeleteFile(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            this.Logger.WriteMessage("DeleteFile: Начало.");

            this.FileAdapter.DeleteFile((FileMetadata)fileMetadata);

            this.Logger.WriteMessage("DeleteFile: Конец.");
        }
コード例 #10
0
ファイル: Blob.cs プロジェクト: soroush01110011/MVP
        /// <summary>
        /// Считывает поток данных файла из блоба.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <returns></returns>
        internal Stream ReadStream(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            //поток закрывает объект, предоставляющий средства потоковой передачи
            FileStream        fs            = this.File.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
            BlobStreamAdapter streamAdapter = new BlobStreamAdapter(fs);
            PartitionStream   stream        = streamAdapter.ReadStream(fileMetadata);

            return(stream);
        }
コード例 #11
0
        internal byte[] Read(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            //содержимое файла
            return(this.ReadContent(
                       fileMetadata.UniqueID,
                       fileMetadata.VersionUniqueID,
                       fileMetadata.BlobStartPosition,
                       fileMetadata.BlobEndPosition));
        }
コード例 #12
0
        public ICollection <IBlobFileVersionMetadata> GetVersions(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            this.Logger.WriteFormatMessage("GetVersions: Начало. fileUniqueID='{0}' folderUrl='{1}'",
                                           fileMetadata.UniqueID, fileMetadata.FolderMetadata.Url);

            FileVersionsCollection collection = ((FileMetadata)fileMetadata).Versions;

            this.Logger.WriteMessage("GetVersions: Конец.");

            return(collection);
        }
コード例 #13
0
        /// <summary>
        /// Считывает поток данных файла.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <returns></returns>
        public Stream ReadFileStream(IFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            this.Logger.WriteFormatMessage("ReadFileStream:Начало чтения содержимого файла, folder.Url: {0}, fileMetadata.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);
            IBlobFileMetadata typedFileMetadata = (IBlobFileMetadata)fileMetadata;
            //получаем контейнер блобов
            Blob   blob   = this.GetBlob(typedFileMetadata.BlobID);
            Stream stream = blob.ReadStream(typedFileMetadata);

            this.Logger.WriteFormatMessage("ReadFileStream:Окончание чтения содержимого файла, folder.Url: {0}, fileMetadata.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);

            return(stream);
        }
コード例 #14
0
        /// <summary>
        /// Возвращает метаданные файла хранилища.
        /// </summary>
        /// <param name="folderMetadata">Метаданные папки.</param>
        /// <param name="fileUniqueID">Уникальный идентификатор файла.</param>
        /// <returns></returns>
        public IFileMetadata ReadFileMetadata(IFolderMetadata folderMetadata, Guid fileUniqueID)
        {
            if (folderMetadata == null)
            {
                throw new ArgumentNullException("folderMetadata");
            }

            if (fileUniqueID == Guid.Empty)
            {
                throw new ArgumentNullException("fileUniqueID");
            }

            this.Logger.WriteFormatMessage("ReadFileMetadata:Начало получения метаданных файла, folder.Url: {0}, fileUniqueID: {1}", folderMetadata.Url, fileUniqueID);
            IBlobFileMetadata fileMetadata = this.BlobMetadataAdapter.GetFile(folderMetadata, fileUniqueID);

            this.Logger.WriteFormatMessage("ReadFileMetadata:Окончание получения метаданных файла, folder.Url: {0}, fileUniqueID: {1}", folderMetadata.Url, fileUniqueID);

            return(fileMetadata);
        }
コード例 #15
0
        internal PartitionStream ReadStream(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.BlobStartPosition >= fileMetadata.BlobEndPosition)
            {
                throw new Exception(string.Format("Индекс начала файла не может быть равным или больше индекса окончания файла"));
            }

            //поток закрывает объект, предоставляющий средства потоковой передачи
            IBlobFileHeader fileHeader           = (IBlobFileHeader)this.GetFileHeader(fileMetadata.BlobStartPosition);
            long            contentStartPosition = fileMetadata.BlobStartPosition + BlobStreamAdapter.SystemHeaderLength + fileHeader.HeaderLength;
            PartitionStream stream = new PartitionStream(this.BlobStream, contentStartPosition, fileMetadata.Size);

            return(stream);
        }
コード例 #16
0
        /// <summary>
        /// Удаляет файл.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <returns></returns>
        public bool DeleteFile(IFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.FolderMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata.FolderMetadata");
            }

            this.Logger.WriteFormatMessage("DeleteFile:Начало удаления файла, folder.Url: {0}, file.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);

            IBlobFileMetadata typedFileMetadata = (IBlobFileMetadata)fileMetadata;

            this.BlobMetadataAdapter.DeleteFile(typedFileMetadata);

            this.Logger.WriteFormatMessage("DeleteFile:Окончание удаления файла, folder.Url: {0}, file.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);

            return(fileMetadata.Deleted);
        }
コード例 #17
0
        /// <summary>
        /// Возвращает коллекцию метаданных версий файла.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <returns></returns>
        public ICollection <IFileVersionMetadata> ReadFileVersionsMetadata(IFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            this.Logger.WriteFormatMessage("ReadFileVersionsMetadata:Начало получения версий файла, folder.Url: {0}, file.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);

            IBlobFileMetadata typedFileMetadata = (IBlobFileMetadata)fileMetadata;
            ICollection <IBlobFileVersionMetadata> fileVersionsMetadata = this.BlobMetadataAdapter.GetVersions(typedFileMetadata);
            List <IFileVersionMetadata>            result = new List <IFileVersionMetadata>();

            if (fileVersionsMetadata != null)
            {
                result.AddRange(fileVersionsMetadata);
            }

            this.Logger.WriteFormatMessage("ReadFileVersionsMetadata:Окончание получения версий файла, folder.Url: {0}, file.UniqueID: {1}", fileMetadata.FolderMetadata.Url, fileMetadata.UniqueID);

            return(result);
        }
コード例 #18
0
        public IFileVersionMetadata WriteRemoteFileVersion(IFileMetadata fileMetadata, IRemoteFile remoteFile)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.FolderMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata.FolderMetadata");
            }

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

            if (remoteFile.Stream == null)
            {
                throw new ArgumentNullException("remoteFile.Stream");
            }

            this.Logger.WriteFormatMessage("WriteFileVersion:Начало записи новой версии файла, fileMetadata.Name: {0}, fileMetadata.UniqueID: {1}", fileMetadata.Name, fileMetadata.UniqueID);

            IBlobFileMetadata blobFileMetadata = (IBlobFileMetadata)fileMetadata;

            if (!string.IsNullOrEmpty(remoteFile.Name))
            {
                blobFileMetadata.Name = remoteFile.Name;
            }

            //резервация параметров сохранения
            blobFileMetadata.EnsureRemoteSaveProperties(remoteFile);

            //запись версии файла
            IFileVersionMetadata savedVersion = this.WriteInternal(blobFileMetadata, remoteFile.Stream, remoteFile.TimeCreated);

            return(savedVersion);
        }
コード例 #19
0
        private IFileVersionMetadata WriteInternal(IBlobFileMetadata blobFileMetadata, Stream stream, DateTime?remoteTimeCreated = null)
        {
            if (blobFileMetadata == null)
            {
                throw new ArgumentNullException("param");
            }

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

            this.Logger.WriteFormatMessage("WriteFile:Начало записи файла, folderMetadata.Name: {0}, fileName: {1}", blobFileMetadata.FolderMetadata.Name, blobFileMetadata.Name);

            //получение контейнера блобов.
            BlobContainer container = this.GetBlobContainer(blobFileMetadata.FolderMetadata);

            //запись файла в контейнер.
            BlobFileInfo blobFileInfo = container.Write(blobFileMetadata, stream, remoteTimeCreated);

            //установка свойств файла, хранящегося в блобе
            blobFileMetadata.BlobID            = blobFileInfo.BlobID;
            blobFileMetadata.BlobStartPosition = blobFileInfo.BlobStartPosition;
            blobFileMetadata.BlobEndPosition   = blobFileInfo.BlobEndPosition;

            this.Logger.WriteMessage("WriteFile:Начало сохранения метаданных файла");
            IBlobFileVersionMetadata savedVersion = this.BlobMetadataAdapter.SaveFile(blobFileMetadata, blobFileInfo.TimeCreated);

            this.Logger.WriteMessage("WriteFile:Окончание сохранения метаданных файла");

            this.Logger.WriteFormatMessage("WriteFile:Начало записи файла, folderMetadata.Name: {0}, fileName: {1}, fileUniqueID: {2}, fileVersionUniqueID: {3}",
                                           blobFileMetadata.FolderMetadata.Name,
                                           blobFileMetadata.Name,
                                           savedVersion.FileMetadata.UniqueID,
                                           savedVersion.UniqueID);

            return(savedVersion);
        }
コード例 #20
0
ファイル: Blob.cs プロジェクト: soroush01110011/MVP
        /// <summary>
        /// Возвращает содержимое файла.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <returns></returns>
        internal byte[] Read(IBlobFileMetadata fileMetadata)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.BlobStartPosition < 0)
            {
                throw new ArgumentNullException("fileMetadata.BlobStartPosition");
            }

            if (fileMetadata.BlobEndPosition < 1)
            {
                throw new ArgumentNullException("fileMetadata.BlobEndPosition");
            }

            this.Container.DataAdapter.Logger.WriteFormatMessage("Blob.Read:Начало чтения содержимого из блоба, blobStartPosition: {0}, blobEndPosition: {1}", fileMetadata.BlobStartPosition, fileMetadata.BlobEndPosition);

            //для операции чтения блоб должен всегда существовать
            if (!this.File.Exists)
            {
                throw new Exception(string.Format("Не удалось найти блоб по пути {0}",
                                                  this.File.FullName));
            }

            byte[] content = null;
            using (FileStream fs = this.File.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                BlobStreamAdapter streamAdapter = new BlobStreamAdapter(fs);
                content = streamAdapter.Read(fileMetadata);
            }
            this.Container.DataAdapter.Logger.WriteFormatMessage("Blob.Read:Окончание чтения содержимого из блоба, blobStartPosition: {0}, blobEndPosition: {1}", fileMetadata.BlobStartPosition, fileMetadata.BlobEndPosition);

            return(content);
        }
コード例 #21
0
ファイル: BlobContainer.cs プロジェクト: soroush01110011/MVP
        /// <summary>
        /// Записывает файл на физический носитель.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <param name="remoteTimeCreated">Время создания версии с удаленного узла.</param>
        /// <returns></returns>
        public BlobFileInfo Write(IBlobFileMetadata fileMetadata, Stream stream, DateTime?remoteTimeCreated = null)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

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

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

            this.Logger.WriteFormatMessage("BlobContainer.Write:Начало записи содержимого файла в блоб, file.UniqueID: {0}", fileMetadata.UniqueID);
            BlobFileInfo blobFileInfo;

            //блоб, на который была получена блокировка для потоковой передачи
            Blob streamingLockedBlob = null;

            try
            {
                //текущий блоб для записи файла
                Blob        currentBlob = null;
                List <Blob> activeBlobs = null;

                //сначала необходимо определить возможно ли осуществить запись
                //в потоковом режиме (не исчерпан ли лимит)
                bool isStreamed             = !stream.CanSeek;
                bool useStreamingLocksLimit = this.DataAdapter.AllowedStreamingLocksLimit != 1;

                if (isStreamed && useStreamingLocksLimit)
                {
                    //проверка на то, что хотя бы 1а потоковая передача может пройти
                    this.ValidateStreamingLocks();

                    //в ситуации, когда одновременно пришло несколько событий потоковой передачи данных
                    //чтобы не лочить все блобы контейнера под запись потоковых файлов и оставить место
                    //под запись буферных файлов делаем проверку на % залоченных под потоковую передачу блобов
                    //потоковая передача данных подразумевает передачу больших файлов
                    object containerLocker = this.GetContainerLocker(ContainerLockerType.StreamingWaiting);
                    lock (containerLocker)
                    {
                        //последняя дата загрузки активных блобов
                        DateTime lastLoadActiveBlobsTime = DateTime.Now;
                        //дата начала ожидания потоковой блокировки текущим потоком
                        DateTime startWaitingStreamingLockTime = DateTime.Now;

                        //вычисляем возможна ли потоковая передача
                        bool limitOverflowed = true;
                        while (limitOverflowed)
                        {
                            //ограничение на продолжительность ожидания блокировки
                            TimeSpan waitingTime = DateTime.Now.Subtract(startWaitingStreamingLockTime);
                            if (waitingTime.TotalMinutes >= BlobConsts.Timeouts.WaitingStreamingLockMinutes)
                            {
                                throw new Exception(string.Format("Истекло время, отведенное на операцию ожидания потоковой блокировки блоба. Дата начала ожидания получения потоковой блокировки {0:dd.MM.yyyy HH:mm:ss}",
                                                                  startWaitingStreamingLockTime));
                            }

                            //перед очередной операцией проверки лимита на потоковые передачи
                            //чтобы не грузить ЦП усыпляем поток
                            Thread.Sleep(50);

                            bool reloadActiveBlobs = activeBlobs == null ||
                                                     DateTime.Now.Subtract(lastLoadActiveBlobsTime).TotalMinutes >= BlobConsts.Timeouts.ReloadActiveBlobsMinutes;

                            if (!reloadActiveBlobs)
                            {
                                //проверяем, что есть закрытые блобы, в выборке, которую получили ранее
                                foreach (Blob tmpBlob in activeBlobs)
                                {
                                    if (tmpBlob.Metadata.Closed)
                                    {
                                        //среди активных блобов появился закрытый во время текущей сессии
                                        //=> необходимо перезагрузить актуальный список.
                                        reloadActiveBlobs = true;
                                        break;
                                    }
                                }
                            }

                            //за время ожидания возмно состав активных блобов изменился
                            if (reloadActiveBlobs)
                            {
                                //выбираем заново список активных блобов
                                activeBlobs             = this.GetActiveBlobs();
                                lastLoadActiveBlobsTime = DateTime.Now;
                            }

                            //кол-во текущих локов, вызванных потоковой передачей
                            //т.к. словарь статический, то lock выше на конейнер недостаточно
                            //поэтому получаем число активных потоковых локов через ф-ию, внутри которой общий lock
                            int containerStreamingLocks = this.GetContainerStreamingLocksCount(activeBlobs);

                            //количество локов, которые будут, если мы заблокируем еще 1 файл текущей передачей
                            int    containerStreamingLocksWithNewLock = containerStreamingLocks + 1;
                            double containerStreamingLocksUsage       = (double)containerStreamingLocksWithNewLock / this.DataAdapter.ActiveBlobsCount;

                            limitOverflowed = containerStreamingLocksUsage > this.DataAdapter.AllowedStreamingLocksLimit;
                        }

                        //вышли из цикла ожидания, значит освободилась как минимум одна ячейка
                        //для выполнения операции потоковой передачи
                        //сразу занимаем эту ячейку
                        currentBlob = this.GetRandomBlob(activeBlobs);
                        this.AddStreamingLock(currentBlob);
                        streamingLockedBlob = currentBlob;
                    }
                }
                else
                {
                    activeBlobs = this.GetActiveBlobs();
                    currentBlob = this.GetRandomBlob(activeBlobs);
                }

                //т.к. общий лок на static переменную это узкое место для записи в разные файлы
                //разные диски и т.п., то на каждый файл в статическом словаре создается свой объект синхронизации
                //таким образом получается, что запись в файл1 НЕ блокирует запись в файл2
                object blobFileLocker = this.GetBlobLocker(currentBlob);
                lock (blobFileLocker)
                {
                    //запись файла в блоб
                    blobFileInfo = currentBlob.Write(fileMetadata, stream, remoteTimeCreated);
                }
            }
            catch (Exception ex)
            {
                string errorMessage = string.Format("BlobContainer.Write:Ошибка записи содержимого файла в блоб, file.UniqueID: {0}, текст ошибки: {1}",
                                                    fileMetadata.UniqueID,
                                                    ex);
                this.Logger.WriteMessage(errorMessage, LogLevel.Error);
                throw ex;
            }
            finally
            {
                if (streamingLockedBlob != null)
                {
                    //за данную операцию была получена блокировка для потоковой передачи.
                    //снимаем ее независимо от успешного результата выполнения операции.
                    this.RemoveStreamingLock(streamingLockedBlob);
                }
            }

            this.Logger.WriteFormatMessage("BlobContainer.Write:Окончание записи содержимого файла в блоб, file.UniqueID: {0}", fileMetadata.UniqueID);

            return(blobFileInfo);
        }
コード例 #22
0
        /// <summary>
        /// Сохраняет содержимое файла с заголовками в поток.
        /// </summary>
        /// <param name="fileMetadata">Метаданные файла.</param>
        /// <param name="stream">Содержимое файла.</param>
        /// <param name="versionTimeCreated">Дата создания версии файла.</param>
        internal void Write(IBlobFileMetadata fileMetadata, Stream stream, DateTime versionTimeCreated)
        {
            if (fileMetadata == null)
            {
                throw new ArgumentNullException("fileMetadata");
            }

            if (fileMetadata.UniqueID == Guid.Empty)
            {
                throw new ArgumentNullException("fileMetadata.UniqueID");
            }

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

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

            if (!this.BlobStream.CanWrite)
            {
                throw new Exception(string.Format("Для сохранения файла в поток необходимо передать поток с правами на запись"));
            }

            bool contentLengthCalculated = false;
            long contentLength           = 0;

            if (stream.CanSeek)
            {
                contentLength           = stream.Length;
                contentLengthCalculated = true;
            }

            byte[] systemHeaderInfoBytes = new byte[BlobStreamAdapter.SystemHeaderLength];
            byte[] headerBytes           = null;
            int    headerLength          = 0;

            //запись текущей версии заголовка
            long blobOffset = this.BlobStream.Position;

            using (MemoryStream fileHeaderStream = new MemoryStream())
            {
                //сериализация заголовка
                this.SerializeHeader(fileHeaderStream, fileMetadata, contentLength, versionTimeCreated);

                //после сериализации заголовка становится известна длина
                headerLength = (int)fileHeaderStream.Length;
                headerBytes  = new byte[headerLength];
                fileHeaderStream.Position = 0;
                fileHeaderStream.Read(headerBytes, 0, headerLength);
            }

            //хеш заголовка и содерижмого
            byte[] headerHash = this.HashAlgorithm.ComputeHash(headerBytes);

            //длина заголовка
            byte[] headerLengthBytes = BitConverter.GetBytes(headerLength);
            //номер версии заголовка
            byte[] headerVersionBytes = BitConverter.GetBytes(BlobConsts.BlobFile.FileHeaderCurrentVersion);


            //заполнение системного заголовка
            //а - фиксированные байты
            int headerCursor = 0;

            Array.Copy(SystemHeaderFixedBytes, 0, systemHeaderInfoBytes, headerCursor, SystemHeaderFixedBytes.Length);
            headerCursor += SystemHeaderFixedBytes.Length;

            //б - размер заголовка файла
            Array.Copy(headerLengthBytes, 0, systemHeaderInfoBytes, headerCursor, headerLengthBytes.Length);
            headerCursor += headerLengthBytes.Length;

            //в - хеш заголовка файла
            Array.Copy(headerHash, 0, systemHeaderInfoBytes, headerCursor, headerHash.Length);
            headerCursor += headerHash.Length;

            //г - хеш содержимого файла
            long tmpcontentHashPosition = this.BlobStream.Position + headerCursor; //абсолютная позиция в файле байтов длины содержимого

            //пустой хеш содержимого, рассчитывается после записи
            byte[] contentHash = new byte[16];
            Array.Copy(contentHash, 0, systemHeaderInfoBytes, headerCursor, contentHash.Length);
            headerCursor += contentHash.Length;

            //д - версия заголовка файла
            Array.Copy(headerVersionBytes, 0, systemHeaderInfoBytes, headerCursor, headerVersionBytes.Length);
            headerCursor += headerVersionBytes.Length;

            //е - размер содержимого файла
            long tmpContentSizePosition = this.BlobStream.Position + headerCursor; //абсолютная позиция в файле байтов длины содержимого

            byte[] contentLengthBytes = BitConverter.GetBytes(contentLength);
            Array.Copy(contentLengthBytes, 0, systemHeaderInfoBytes, headerCursor, contentLengthBytes.Length);
            headerCursor += contentLengthBytes.Length;

            //1 - запись системного заголовка
            this.BlobStream.Write(systemHeaderInfoBytes, 0, systemHeaderInfoBytes.Length);

            //2 - запись заголовка файла
            this.BlobStream.Write(headerBytes, 0, headerBytes.Length);

            //3 - запись содержимого
            long startContentPosition = this.BlobStream.Position;

            int readBufferSize = 4 * 1024;

            byte[]        buffer           = new byte[readBufferSize];
            int           read             = 0;
            HashAlgorithm tmpHashAlgorithm = this.CreateHashAlgorithm();

            byte[] writeBuffer = new byte[readBufferSize];

            int writePosition = 0;

            while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                tmpHashAlgorithm.TransformBlock(buffer, 0, read, null, 0);

                if ((writePosition + read) >= writeBuffer.Length)
                {
                    //дозаполняем буфер
                    int restBufferSize = writeBuffer.Length - writePosition;
                    Array.Copy(buffer, 0, writeBuffer, writePosition, restBufferSize);
                    writePosition += restBufferSize;

                    //скидываем буфер записи на диск
                    this.BlobStream.Write(writeBuffer, 0, writePosition);

                    int newSessionPosition = read - restBufferSize;
                    if (newSessionPosition > 0)
                    {
                        //остальные данные опять загоняем в буфер
                        Array.Copy(buffer, restBufferSize, writeBuffer, 0, newSessionPosition);
                    }

                    writePosition = newSessionPosition;
                }
                else
                {
                    //записываем только в буфер, на диск не скидываем
                    Array.Copy(buffer, 0, writeBuffer, writePosition, read);
                    writePosition += read;
                }
            }

            if (writePosition > 0)
            {
                this.BlobStream.Write(writeBuffer, 0, writePosition);
            }

            tmpHashAlgorithm.TransformFinalBlock(buffer, 0, read);


            //физически записанная длина файла
            long endContentPosition = this.BlobStream.Position;

            contentLength = endContentPosition - startContentPosition;

            //4 - переписываем 16 пустых байт хеша содержимого, после его вычисления
            contentHash = tmpHashAlgorithm.Hash;
            long contentHashBytesAbsolutePosition = FileStructure.GetContentHashBytesAbsolutePosition(blobOffset);

            this.BlobStream.Seek(contentHashBytesAbsolutePosition, SeekOrigin.Begin);
            this.BlobStream.Write(contentHash, 0, contentHash.Length);


            //5 - в 100 зарезервированных байт пишем длину содержимого (ранее была в заголовке)
            //теперь обязательно есть в системном заголовке, а в файловом заголовке есть, если пришел буферный поток
            //делаем это только в случае потоковой передачи, если длина известна сразу, то она и запишется сразу
            if (!contentLengthCalculated)
            {
                long contentLengBytesAbsolutePosition = FileStructure.GetContentLengBytesAbsolutePosition(blobOffset);
                contentLengthBytes = BitConverter.GetBytes(contentLength);
                this.BlobStream.Seek(contentLengBytesAbsolutePosition, SeekOrigin.Begin);
                this.BlobStream.Write(contentLengthBytes, 0, contentLengthBytes.Length);
            }

            fileMetadata.Size = contentLength;
        }