Ejemplo n.º 1
0
        /// <summary>
        /// Write entries directory to pages. If pages not enough for new directory - additional pages will allocated.
        /// Also write header and pageAllocator state
        /// </summary>
        public void Write(Stream stm, PagedContainerHeader header, PageAllocator pageAllocator)
        {
            var targetPages = pages;

            var buff = entries.WriteEntries(header.DataHandler);

            var requiredPages = header.GetRequiredPages(buff.Length);

            if (requiredPages > targetPages.Length) // need to allocate additional pages?
            {
                targetPages = targetPages.Concat(pageAllocator.AllocatePages(requiredPages - targetPages.Length)).ToArray();
            }
            else if (requiredPages < targetPages.Length) // can free unused pages?
            {
                var mustBeFreePages = targetPages.Skip(requiredPages).ToArray();
                targetPages = targetPages.Take(requiredPages).ToArray();

                pageAllocator.FreePages(mustBeFreePages);
            }

            stm.WriteIntoPages(header, buff, 0, targetPages);

            header.DirectoryFirstPage = targetPages[0];
            header.Write(stm);

            pageAllocator.Write(stm);

            pages = targetPages;
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Write buffer to targetPages.
        /// Last of 32 bit of each page contain next page index.
        /// Last page in sequence contain next page index == 0
        /// </summary>
        internal static void WriteIntoPages(this Stream stm, PagedContainerHeader header, Span <byte> data, int offset, int[] targetPages)
        {
            var currentPageIndex = 0;

            var page = new byte[header.PageSize].AsSpan();

            foreach (var pageIndex in targetPages)
            {
                var writeLength = data.Length - offset;
                if (writeLength > header.PageUserDataSize)
                {
                    data.Slice(offset, header.PageUserDataSize).CopyTo(page);
                    offset += header.PageUserDataSize;
                }
                else
                {
                    page.Clear();
                    data.Slice(offset, writeLength).CopyTo(page);
                    offset += writeLength;
                }

                BitConverter.TryWriteBytes(page.Slice(header.PageUserDataSize),
                                           currentPageIndex + 1 < targetPages.Length ? targetPages[currentPageIndex + 1] : 0);

                var newPosition = header.PageSize * pageIndex;
                if (newPosition != stm.Position)
                {
                    stm.Position = newPosition;
                }
                stm.Write(page);

                currentPageIndex++;
            }
        }
Ejemplo n.º 3
0
        protected PagedContainerAbstract(Stream stm, PersistentContainerSettings?settings = null)
        {
            Stream = stm;
            settings ??= new PersistentContainerSettings();
            try
            {
                if (stm.Length == 0) // new file
                {
                    Header = new PagedContainerHeader(settings);
                    Header.Write(stm);

                    pageAllocator = new PageAllocator(Header);
                    pageAllocator.Write(stm);
                }
                else
                {
                    Header        = new PagedContainerHeader(stm, settings.encryptorDecryptor);
                    pageAllocator = new PageAllocator(Header, stm);
                }

                entries = Header.DirectoryFirstPage == 0
                    ? new PagedContainerEntryCollection()
                    : new PagedContainerEntryCollection(Header, stm.ReadWithPageSequence(Header, Header.DirectoryFirstPage));
            }
            catch
            {
                Dispose();
                throw;
            }
        }
Ejemplo n.º 4
0
        public PageAllocator(PagedContainerHeader header, Stream stm)
        {
            this.header = header;

            var buff = stm.ReadWithPageSequence(header, FIRST_PA_PAGE).Data;

            pageAllocations = new ExpandableBitArray(header.DataHandler.Unpack(buff).ToArray());
        }
Ejemplo n.º 5
0
        public PageAllocator(PagedContainerHeader header)
        {
            this.header = header;

            pageAllocations    = new ExpandableBitArray(2);
            pageAllocations[0] = true;
            pageAllocations[1] = true;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Read only sequence page numbers from 'startFromPage'.
        /// Last 32 bit contain next page index.
        /// Last page in sequence contain 'next page index' value == 0
        /// </summary>
        internal static int[] ReadPageSequence(this Stream stm, PagedContainerHeader header, int startFromPage)
        {
            var pages = new List <int>();

            var buff             = new byte[4];
            var currentPageIndex = startFromPage;

            while (currentPageIndex > 0)
            {
                pages.Add(currentPageIndex);

                stm.Position = currentPageIndex * header.PageSize + header.PageUserDataSize;
                stm.Read(buff, 0, 4);

                currentPageIndex = BitConverter.ToInt32(buff, 0);
            }

            return(pages.ToArray());
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Read data and page numbers, starting from 'startFromPage'
        /// Used in PageAllocator & PagedContainerEntryCollection
        /// </summary>
        internal static PageSequence ReadWithPageSequence(this Stream stm, PagedContainerHeader header, int startFromPage)
        {
            using var stmCollector = new MemoryStream();

            var pages = new List <int>();
            var buff  = new byte[header.PageSize];

            while (startFromPage > 0)
            {
                pages.Add(startFromPage);
                stm.Position = startFromPage * header.PageSize;
                stm.Read(buff, 0, header.PageSize);

                stmCollector.Write(buff, 0, header.PageUserDataSize);
                startFromPage = BitConverter.ToInt32(buff, header.PageUserDataSize);
            }

            return(new PageSequence(stmCollector.ToArray(), pages.ToArray()));
        }
Ejemplo n.º 8
0
        /// <summary> Read data from pages, starting with entry.FirstPage </summary>
        internal static byte[] ReadEntryPageSequence(this Stream stm, PagedContainerHeader header, PagedContainerEntry entry)
        {
            using var stmCollector = new MemoryStream(entry.Length); // todo replace with byte[]

            var remainLength     = entry.Flags.HasFlag(EntryFlags.Compressed) ? entry.CompressedLength : entry.Length;
            var currentPageIndex = entry.FirstPage;
            var buff             = new byte[header.PageSize];

            while (currentPageIndex > 0)
            {
                stm.Position = currentPageIndex * header.PageSize;
                stm.Read(buff, 0, header.PageSize);

                var requestLength = remainLength > header.PageUserDataSize ? header.PageUserDataSize : remainLength;
                stmCollector.Write(buff, 0, requestLength);
                remainLength -= requestLength;

                currentPageIndex = BitConverter.ToInt32(buff, header.PageUserDataSize);
            }

            return(header.DataHandler.Unpack(stmCollector.ToArray()).ToArray());
        }
Ejemplo n.º 9
0
 internal PagedContainerEntryCollection(PagedContainerHeader header, PageSequence ps)
 {
     entries  = ps.Data.ReadEntries(header.DataHandler);
     pages    = ps.Pages;
     Modified = false;
 }