private void WriteFiller(uint word, int count) { Contract.Requires(count > 0); uint previous = m_current; if (previous == word) { // continuation of current run m_counter += count; return; } if (previous == NO_VALUE) { // start of new run m_counter += count; m_current = word; return; } // switch from one type to the other m_words += m_counter; if (previous == CompressedWord.ALL_ZEROES) { m_writer.WriteFixed32(CompressedWord.MakeZeroes(m_counter)); } else { m_writer.WriteFixed32(CompressedWord.MakeOnes(m_counter)); } m_counter = count; }
internal static Slice Pack([NotNull] CompressedWord[] words, int size, int highest) { Contract.Requires(size >= 0 && size <= words.Length); if (size == 0) { // empty bitmap return(Slice.Empty); } var writer = new SliceWriter(checked ((size + 1) << 2)); writer.WriteFixed32(CompressedWord.MakeHeader(highest)); for (int i = 0; i < size; i++) { writer.WriteFixed32(words[i].RawValue); } return(writer.ToSlice()); }
/// <summary>Write the header to the file</summary> /// <param name="headerFlags"></param> /// <param name="uid"></param> /// <param name="sequence"></param> /// <param name="count"></param> /// <param name="timestamp"></param> /// <param name="attributes"></param> /// <remarks>This needs to be called before writing any level to the file</remarks> public Task WriteHeaderAsync(SnapshotFormat.Flags headerFlags, Uuid128 uid, ulong sequence, long count, long timestamp, IDictionary <string, IFdbTuple> attributes) { // The header will be use on ore more "pages", to simplify the job of loading / peeking at a stream content (no need for fancy buffering, just need to read 4K pages) // > The last page is padded with 0xAAs to detect corruption. m_uid = uid; m_sequence = sequence; m_itemCount = count; m_timestamp = timestamp; // HEADER // - DB_HEADER (64 bytes) // - DB ATTRIBUTES (variable size list of k/v) // - END_MARKER + HEADER_CRC // - PADDING (to fill last page) // DB Header // "PNDB" m_writer.WriteFixed32(SnapshotFormat.HEADER_MAGIC_NUMBER); // v1.0 m_writer.WriteFixed16(1); // major m_writer.WriteFixed16(0); // minor // FLAGS m_writer.WriteFixed64((ulong)headerFlags); // Database ID m_writer.WriteBytes(uid.ToSlice()); // Database Version m_writer.WriteFixed64(sequence); // Number of items in the database m_writer.WriteFixed64((ulong)count); // Database Timestamp m_writer.WriteFixed64((ulong)timestamp); // Page Size m_writer.WriteFixed32(SnapshotFormat.PAGE_SIZE); // Header Size (not known yet and will be filled in later) int offsetToHeaderSize = m_writer.Skip(4); // we should be at the 64 byte mark Contract.Assert(m_writer.Position == SnapshotFormat.HEADER_METADATA_BYTES); // DB Attributes m_writer.WriteFixed32((uint)attributes.Count); foreach (var kvp in attributes) { // Name m_writer.WriteVarbytes(Slice.FromString(kvp.Key)); // Value m_writer.WriteVarbytes(kvp.Value.ToSlice()); } // Mark the end of the header m_writer.WriteFixed32(uint.MaxValue); // we now have the size of the header, and can fill in the blank var headerEnd = m_writer.Position; m_writer.Position = offsetToHeaderSize; // write the header size (includes the CRC) m_writer.WriteFixed32((uint)checked (headerEnd + SnapshotFormat.HEADER_CRC_SIZE)); m_writer.Position = headerEnd; // now we can compute the actual CRC uint headerChecksum = SnapshotFormat.ComputeChecksum(m_writer.ToSlice()); m_writer.WriteFixed32(headerChecksum); m_headerChecksum = headerChecksum; // optional padding to fill the rest of the page PadPageIfNeeded(SnapshotFormat.PAGE_SIZE, 0xFD); return(TaskHelpers.CompletedTask); }