public static bool StillAlive(Key* self, ulong sequence)
		{
			if (self == null) return false;

			if ((self->Header & Entry.FLAGS_UNREACHABLE) != 0)
			{ // we have been marked as dead

				var value = self->Values;
				if (value == null) return false;

				// check if the last value is a deletion?
				if (value->Sequence <= sequence && (value->Header & Value.FLAGS_DELETION) != 0)
				{ // it is deleted
					return false;
				}
			}

			return true;
		}
		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));

		}
		/// <summary>Return the address of the following value in the heap</summary>
		internal static Key* WalkNext(Key* self)
		{
			Contract.Requires(self != null && Entry.GetObjectType(self) == EntryType.Key);

			return (Key*)Entry.Align((byte*)self + Key.SizeOf + self->Size);
		}
		public static bool IsDisposed(Key* self)
		{
			return (self->Header & Entry.FLAGS_DISPOSED) != 0;
		}
		public static USlice GetData(Key* self)
		{
			if (self == null) return default(USlice);
			Contract.Assert((self->Header & Entry.FLAGS_DISPOSED) == 0, "Attempt to read a key that was disposed");
			return new USlice(&(self->Data), self->Size);
		}