<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using static LiteDB.Constants;

namespace LiteDB.Engine
{
    public enum PageType { Empty = 0, Header = 1, CollectionList = 6, Collection = 2, Index = 3, Data = 4, Extend = 5 }

    internal abstract class BasePage
    {
        /// <summary>
        /// Represent page number - start in 0 with HeaderPage [4 bytes]
        /// </summary>
        public uint PageID { get; set; }

        /// <summary>
        /// Indicate the page type [1 byte] - Must be implemented for each page type
        /// </summary>
        public abstract PageType PageType { get; }

        /// <summary>
        /// Represent the previous page. Used for page-sequences - MaxValue represent that has NO previous page [4 bytes]
        /// </summary>
        public uint PrevPageID { get; set; }

        /// <summary>
        /// Represent the next page. Used for page-sequences - MaxValue represent that has NO next page [4 bytes]
        /// </summary>
        public uint NextPageID { get; set; }

        /// <summary>
        /// Used for all pages to count items inside this page(bytes, nodes, blocks, ...) [2 bytes]
        /// Its Int32 but writes in UInt16
        /// </summary>
        public int ItemCount { get; set; }

        /// <summary>
        /// Used to find a free page using only header search [used in FreeList] [2 bytes]
        /// Its Int32 but writes in UInt16
        /// Its updated when a page modify content length (add/remove items)
        /// </summary>
        public int FreeBytes { get; set; }

        /// <summary>
        /// Represent transaction page ID that was stored [16 bytes]
        /// </summary>
        public Guid TransactionID { get; set; }

        /// <summary>
        /// Set in all datafile pages the page id about data/index collection. Useful if want re-build database without any index
        /// </summary>
        public uint ColID { get; set; }

        /// <summary>
        /// Set this pages that was changed and must be persist in disk [not peristable]
        /// </summary>
        public bool IsDirty { get; set; }

        public BasePage()
        {
        }

        public BasePage(uint pageID)
        {
            this.PageID = pageID;
            this.PrevPageID = uint.MaxValue;
            this.NextPageID = uint.MaxValue;
            this.ItemCount = 0;
            this.FreeBytes = PAGE_AVAILABLE_BYTES;
            this.TransactionID = Guid.Empty;
            this.ColID = uint.MaxValue;
            this.IsDirty = false;
        }

        #region Read/Write page

        /// <summary>
        /// Write a page to byte array
        /// </summary>
        public void WritePage(BinaryWriter writer)
        {
            var start = writer.BaseStream.Position;

            this.WriteHeader(writer);
            this.WriteContent(writer);

            // padding end of page with 0 byte
            var length = PAGE_SIZE - (writer.BaseStream.Position - start);

            if (length > 0)
            {
                writer.Write(new byte[length]);
            }

            DEBUG(length < 0, "Page overflow. Current page exceeded 8192 bytes.");
        }

        private void ReadHeader(BinaryReader reader)
        {
            // first 5 bytes (pageID + pageType) was read before class create by [static ReadPage(long position)]
            // this.PageID // 4 bytes
            // this.PageType // 1 byte

            this.PrevPageID = reader.ReadUInt32(); // 4 bytes
            this.NextPageID = reader.ReadUInt32(); // 4 bytes
            this.ItemCount = reader.ReadUInt16(); // 2 bytes
            this.FreeBytes = reader.ReadUInt16(); // 2 bytes
            this.TransactionID = reader.ReadGuid(); // 16 bytes
            this.ColID = reader.ReadUInt32(); // 4 bytes

            reader.ReadBytes(27); // reserved 27 bytes
        }

        private void WriteHeader(BinaryWriter writer)
        {
            writer.Write(this.PageID);
            writer.Write((byte)this.PageType);

            writer.Write(this.PrevPageID);
            writer.Write(this.NextPageID);
            writer.Write((UInt16)this.ItemCount);
            writer.Write((UInt16)this.FreeBytes);
            writer.Write(this.TransactionID);
            writer.Write(this.ColID);

            writer.Write(new byte[27]);
        }

        protected abstract void ReadContent(BinaryReader reader, bool utcDate);

        protected abstract void WriteContent(BinaryWriter writer);

        #endregion

        #region Static Helper Methods

        /// <summary>
        /// Returns a size of specified number of pages
        /// </summary>
        public static long GetPagePosition(uint pageID)
        {
            return checked((long)pageID * PAGE_SIZE);<commit_msg>Create _zeroBuffer to reuse in page<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using static LiteDB.Constants;

namespace LiteDB.Engine
{
    public enum PageType { Empty = 0, Header = 1, CollectionList = 6, Collection = 2, Index = 3, Data = 4, Extend = 5 }

    internal abstract class BasePage
    {
        /// <summary>
        /// Create a re-usable buffer with zero value
        /// </summary>
        private static byte[] _zeroBuffer = new byte[PAGE_SIZE];

        /// <summary>
        /// Represent page number - start in 0 with HeaderPage [4 bytes]
        /// </summary>
        public uint PageID { get; set; }

        /// <summary>
        /// Indicate the page type [1 byte] - Must be implemented for each page type
        /// </summary>
        public abstract PageType PageType { get; }

        /// <summary>
        /// Represent the previous page. Used for page-sequences - MaxValue represent that has NO previous page [4 bytes]
        /// </summary>
        public uint PrevPageID { get; set; }

        /// <summary>
        /// Represent the next page. Used for page-sequences - MaxValue represent that has NO next page [4 bytes]
        /// </summary>
        public uint NextPageID { get; set; }

        /// <summary>
        /// Used for all pages to count items inside this page(bytes, nodes, blocks, ...) [2 bytes]
        /// Its Int32 but writes in UInt16
        /// </summary>
        public int ItemCount { get; set; }

        /// <summary>
        /// Used to find a free page using only header search [used in FreeList] [2 bytes]
        /// Its Int32 but writes in UInt16
        /// Its updated when a page modify content length (add/remove items)
        /// </summary>
        public int FreeBytes { get; set; }

        /// <summary>
        /// Represent transaction page ID that was stored [16 bytes]
        /// </summary>
        public Guid TransactionID { get; set; }

        /// <summary>
        /// Set in all datafile pages the page id about data/index collection. Useful if want re-build database without any index
        /// </summary>
        public uint ColID { get; set; }

        /// <summary>
        /// Set this pages that was changed and must be persist in disk [not peristable]
        /// </summary>
        public bool IsDirty { get; set; }

        public BasePage()
        {
        }

        public BasePage(uint pageID)
        {
            this.PageID = pageID;
            this.PrevPageID = uint.MaxValue;
            this.NextPageID = uint.MaxValue;
            this.ItemCount = 0;
            this.FreeBytes = PAGE_AVAILABLE_BYTES;
            this.TransactionID = Guid.Empty;
            this.ColID = uint.MaxValue;
            this.IsDirty = false;
        }

        #region Read/Write page

        /// <summary>
        /// Write a page to byte array
        /// </summary>
        public void WritePage(BinaryWriter writer)
        {
            var start = writer.BaseStream.Position;

            this.WriteHeader(writer);
            this.WriteContent(writer);

            // padding end of page with 0 byte
            var length = PAGE_SIZE - (writer.BaseStream.Position - start);

            if (length > 0)
            {
                writer.Write(_zeroBuffer, 0, (int)length);
            }

            DEBUG(length < 0, "Page overflow. Current page exceeded 8192 bytes.");
        }

        private void ReadHeader(BinaryReader reader)
        {
            // first 5 bytes (pageID + pageType) was read before class create by [static ReadPage(long position)]
            // this.PageID // 4 bytes
            // this.PageType // 1 byte

            this.PrevPageID = reader.ReadUInt32(); // 4 bytes
            this.NextPageID = reader.ReadUInt32(); // 4 bytes
            this.ItemCount = reader.ReadUInt16(); // 2 bytes
            this.FreeBytes = reader.ReadUInt16(); // 2 bytes
            this.TransactionID = reader.ReadGuid(); // 16 bytes
            this.ColID = reader.ReadUInt32(); // 4 bytes

            reader.BaseStream.Position += 27;  // reserved 27 bytes
                                               // total header: 64 bytes
        }

        private void WriteHeader(BinaryWriter writer)
        {
            writer.Write(this.PageID); // 4 bytes
            writer.Write((byte)this.PageType); // 1 byte

            writer.Write(this.PrevPageID); // 4 bytes
            writer.Write(this.NextPageID); // 4 bytes
            writer.Write((UInt16)this.ItemCount); // 2 bytes
            writer.Write((UInt16)this.FreeBytes); // 2 bytes
            writer.Write(this.TransactionID); // 16 bytes
            writer.Write(this.ColID); // 4 bytes

            writer.Write(_zeroBuffer, 0, 27); // 27 bytes
                                              // total header: 64 bytes
        }

        protected abstract void ReadContent(BinaryReader reader, bool utcDate);

        protected abstract void WriteContent(BinaryWriter writer);

        #endregion

        #region Static Helper Methods

        /// <summary>
        /// Returns a size of specified number of pages
        /// </summary>
        public static long GetPagePosition(uint pageID)
        {
            return checked((long)pageID * PAGE_SIZE);
{'fraction_non_alphanumeric': 0.10443915973047958, 'fraction_numerical': 0.013971462544589775, 'mean_word_length': 1.656751776783364, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5501598', 'n_tokens_mistral': 2720, 'n_tokens_neox': 2539, 'n_words': 870}