public Task WriteJumpTableAsync(CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            // The jump table is the last page of the file
            // - it contains the list of (offset, size) of all the levels that are in the file
            // - it contains any additional attributes (that were only known after writing all the data)
            // - it repeats a few important values (sequence, header crc, ...)
            // - it would contain any optional signature or data that is only know after writing the data to disk, and are needed to decode the rest

            // marks the start of the JT because we will need to compute the checksum later on
            int startOffset = m_writer.Position;

            // "JMPT"
            m_writer.WriteFixed32(SnapshotFormat.JUMP_TABLE_MAGIC_NUMBER);
            // Page Size (repeated)
            m_writer.WriteFixed32((uint)m_pageSize);
            // Sequence Number (repeated)
            m_writer.WriteFixed64(m_sequence);
            // Database ID (repeated)
            m_writer.WriteBytes(m_uid.ToSlice());
            // Header CRC (repeated)
            m_writer.WriteFixed32(m_headerChecksum);

            int levels = m_levels;

            m_writer.WriteFixed32((uint)levels);                                // Level Count
            for (int level = 0; level < levels; level++)
            {
                // Level Offset (from start of file)
                m_writer.WriteFixed64((ulong)m_jumpTable[level].Key);
                // Level Size (in bytes)
                m_writer.WriteFixed64((ulong)m_jumpTable[level].Value);
            }

            //TODO: additional attributes!
            m_writer.WriteFixed32(0);             // 0 for now

            // End Marker
            m_writer.WriteFixed32(uint.MaxValue);

            // Checksum
            int  endOffset         = m_writer.Position;
            uint jumpTableChecksum = SnapshotFormat.ComputeChecksum(m_writer[startOffset, endOffset]);

            m_writer.WriteFixed32(jumpTableChecksum);

            // optional padding to fill the rest of the page
            PadPageIfNeeded(SnapshotFormat.PAGE_SIZE, 0xFE);

            // we are done !
            return(TaskHelpers.CompletedTask);
        }
		/// <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;
		}
        /// <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);
        }