public async Task WriteLevelAsync(int level, IntPtr[] segment, CancellationToken ct) { ct.ThrowIfCancellationRequested(); if (m_jumpTable[level].Value > 0) { throw new InvalidOperationException("The level has already be written to this snapshot"); } var levelStart = checked (m_file.Length + (uint)m_writer.Position); //Console.WriteLine("## level " + level + " starts at " + levelStart); //TODO: ensure that we start on a PAGE? //Console.WriteLine("> Writing level " + level); // "LVL_" m_writer.WriteFixed32(SnapshotFormat.LEVEL_MAGIC_NUMBER); // Level Flags m_writer.WriteFixed32(0); //TODO: flags! // Level ID m_writer.WriteFixed32((uint)level); // Item count (always 2^level) m_writer.WriteFixed32((uint)segment.Length); for (int i = 0; i < segment.Length; i++) { unsafe { #if __MonoCS__ var valuePointer = new IntPtr((void *)MemoryDatabaseHandler.ResolveValueAtVersion(segment[i], m_sequence)); if (valuePointer == IntPtr.Zero) { continue; } Value value = new Value(); Marshal.PtrToStructure(valuePointer, value); var keyPointer = new IntPtr((void *)segment[i]); Key key = new Key(); Marshal.PtrToStructure(keyPointer, key); Contract.Assert(key.Size <= MemoryDatabaseHandler.MAX_KEY_SIZE); // Key Size uint size = key.Size; m_writer.WriteVarint32(size); m_writer.WriteBytesUnsafe(&(key.Data), (int)size); // Value m_writer.WriteVarint64(value.Sequence); // sequence size = value.Size; if (size == 0) { // empty key m_writer.WriteByte(0); } else { m_writer.WriteVarint32(size); // value size m_writer.WriteBytesUnsafe(&(value.Data), (int)size); // value data } #else Value *value = MemoryDatabaseHandler.ResolveValueAtVersion(segment[i], m_sequence); if (value == null) { continue; } Key *key = (Key *)segment[i]; //.ToPointer(); Contract.Assert(key != null && key->Size <= MemoryDatabaseHandler.MAX_KEY_SIZE); // Key Size uint size = key->Size; m_writer.WriteVarint32(size); m_writer.WriteBytesUnsafe(&(key->Data), (int)size); // Value m_writer.WriteVarint64(value->Sequence); // sequence size = value->Size; if (size == 0) { // empty key m_writer.WriteByte(0); } else { m_writer.WriteVarint32(size); // value size m_writer.WriteBytesUnsafe(&(value->Data), (int)size); // value data } #endif } if (m_writer.Position >= SnapshotFormat.FLUSH_SIZE) { //Console.WriteLine("> partial flush (" + writer.Position + ")"); int written = await m_file.WriteCompletePagesAsync(m_writer.Buffer, m_writer.Position, ct).ConfigureAwait(false); if (written > 0) { m_writer.Flush(written); } } } m_writer.WriteFixed32(uint.MaxValue); //TODO: CRC? (would need to be computed on the fly, because we don't have the full slice in memory probably) m_writer.WriteFixed32(0); var levelEnd = checked (m_file.Length + (uint)m_writer.Position); m_jumpTable[level] = new KeyValuePair <ulong, ulong>(levelStart, levelEnd - levelStart); //Console.WriteLine("## level " + level + " ends at " + levelEnd); // optional padding to fill the rest of the page PadPageIfNeeded(SnapshotFormat.PAGE_SIZE, (byte)(0xFC - level)); }