/// <summary>
        /// <see cref="IDevice.ReadAsync(int, ulong, IntPtr, uint, IOCompletionCallback, IAsyncResult)">Inherited</see>
        /// </summary>
        public override unsafe void ReadAsync(int segmentId, ulong sourceAddress, IntPtr destinationAddress, uint readLength, IOCompletionCallback callback, IAsyncResult asyncResult)
        {
            // It is up to the allocator to make sure no reads are issued to segments before they are written
            if (!blobs.TryGetValue(segmentId, out BlobEntry blobEntry))
            {
                throw new InvalidOperationException("Attempting to read non-existent segments");
            }

            // Even though Azure Page Blob does not make use of Overlapped, we populate one to conform to the callback API
            Overlapped        ov       = new Overlapped(0, 0, IntPtr.Zero, asyncResult);
            NativeOverlapped *ovNative = ov.UnsafePack(callback, IntPtr.Zero);

            UnmanagedMemoryStream stream   = new UnmanagedMemoryStream((byte *)destinationAddress, readLength, readLength, FileAccess.Write);
            CloudPageBlob         pageBlob = blobEntry.GetPageBlob();

            pageBlob.BeginDownloadRangeToStream(stream, (Int64)sourceAddress, readLength, ar => {
                try
                {
                    pageBlob.EndDownloadRangeToStream(ar);
                }
                // I don't think I can be more specific in catch here because no documentation on exception behavior is provided
                catch (Exception e)
                {
                    Trace.TraceError(e.Message);
                    // Is there any documentation on the meaning of error codes here? The handler suggests that any non-zero value is an error
                    // but does not distinguish between them.
                    callback(2, readLength, ovNative);
                }
                callback(0, readLength, ovNative);
            }, asyncResult);
        }