private void ClearPage(int page, bool pageZero) { if (Key.HasObjectsToSerialize() || Value.HasObjectsToSerialize()) { long ptr = (long)pointers[page]; int numBytes = PageSize; long endptr = ptr + numBytes; if (pageZero) { ptr += Constants.kFirstValidAddress; } List <long> addr = new List <long>(); while (ptr < endptr) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key *key = Layout.GetKey(ptr); Key.Free(key); } if (Value.HasObjectsToSerialize()) { Value *value = Layout.GetValue(ptr); Value.Free(value); } } ptr += Layout.GetPhysicalSize(ptr); } } Array.Clear(values[page], 0, values[page].Length); }
/// <summary> /// Deseialize part of page from stream /// </summary> /// <param name="ptr">From pointer</param> /// <param name="untilptr">Until pointer</param> /// <param name="stream">Stream</param> public void Deserialize(long ptr, long untilptr, Stream stream) { while (ptr < untilptr) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key.Deserialize(Layout.GetKey(ptr), stream); } if (Value.HasObjectsToSerialize()) { Value.Deserialize(Layout.GetValue(ptr), stream); } } ptr += Layout.GetPhysicalSize(ptr); } }
/// <summary> /// Clear page /// </summary> /// <param name="ptr">From pointer</param> /// <param name="endptr">Until pointer</param> public void ClearPage(long ptr, long endptr) { while (ptr < endptr) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key *key = Layout.GetKey(ptr); Key.Free(key); } if (Value.HasObjectsToSerialize()) { Value *value = Layout.GetValue(ptr); Value.Free(value); } } ptr += Layout.GetPhysicalSize(ptr); } }
internal bool GetLogicalAddress(Key *key, out long logicalAddress) { var bucket = default(HashBucket *); var slot = default(int); logicalAddress = Constants.kInvalidAddress; var physicalAddress = default(long); var info = default(RecordInfo *); var hash = Key.GetHashCode(key); var tag = (ushort)((ulong)hash >> Constants.kHashTagShift); var entry = default(HashBucketEntry); var tagExists = FindTag(hash, tag, ref bucket, ref slot, ref entry); if (tagExists) { logicalAddress = entry.word & Constants.kAddressMask; Debug.Assert(logicalAddress != 0); if (logicalAddress >= hlog.HeadAddress) { physicalAddress = hlog.GetPhysicalAddress(logicalAddress); if (!Key.Equals(key, Layout.GetKey(physicalAddress))) { logicalAddress = Layout.GetInfo(physicalAddress)->PreviousAddress; TraceBackForKeyMatch(key, logicalAddress, hlog.HeadAddress, out logicalAddress, out physicalAddress); } } } if (logicalAddress < hlog.HeadAddress && logicalAddress != Constants.kInvalidAddress) { return(false); } return(true); }
/// <summary> /// Serialize part of page to stream /// </summary> /// <param name="ptr">From pointer</param> /// <param name="untilptr">Until pointer</param> /// <param name="stream">Stream</param> /// <param name="objectBlockSize">Size of blocks to serialize in chunks of</param> /// <param name="addr">List of addresses that need to be updated with offsets</param> public void Serialize(ref long ptr, long untilptr, Stream stream, int objectBlockSize, out List <long> addr) { addr = new List <long>(); while (ptr < untilptr) { if (!Layout.GetInfo(ptr)->Invalid) { long pos = stream.Position; if (Key.HasObjectsToSerialize()) { Key *key = Layout.GetKey(ptr); Key.Serialize(key, stream); ((AddressInfo *)key)->Address = pos; ((AddressInfo *)key)->Size = (int)(stream.Position - pos); addr.Add((long)key); } if (Value.HasObjectsToSerialize()) { pos = stream.Position; Value *value = Layout.GetValue(ptr); Value.Serialize(value, stream); ((AddressInfo *)value)->Address = pos; ((AddressInfo *)value)->Size = (int)(stream.Position - pos); addr.Add((long)value); } } ptr += Layout.GetPhysicalSize(ptr); if (stream.Position > objectBlockSize) { return; } } }
private void RecoverFromPage(long startRecoveryAddress, long fromLogicalAddressInPage, long untilLogicalAddressInPage, long pageLogicalAddress, long pagePhysicalAddress, int version) { var key = default(Key *); var hash = default(long); var tag = default(ushort); var info = default(RecordInfo *); var pointer = default(long); var recordStart = default(long); var bucket = default(HashBucket *); var entry = default(HashBucketEntry); var slot = default(int); pointer = fromLogicalAddressInPage; while (pointer < untilLogicalAddressInPage) { recordStart = pagePhysicalAddress + pointer; info = Layout.GetInfo(recordStart); if (info->IsNull()) { pointer += RecordInfo.GetLength(); continue; } if (!info->Invalid) { key = Layout.GetKey(recordStart); hash = Key.GetHashCode(key); tag = (ushort)((ulong)hash >> Constants.kHashTagShift); entry = default(HashBucketEntry); FindOrCreateTag(hash, tag, ref bucket, ref slot, ref entry); if (info->Version <= version) { entry.Address = pageLogicalAddress + pointer; entry.Tag = tag; entry.Pending = false; entry.Tentative = false; bucket->bucket_entries[slot] = entry.word; } else { info->Invalid = true; if (info->PreviousAddress < startRecoveryAddress) { entry.Address = info->PreviousAddress; entry.Tag = tag; entry.Pending = false; entry.Tentative = false; bucket->bucket_entries[slot] = entry.word; } } } pointer += Layout.GetPhysicalSize(recordStart); } }
private void AsyncReadPageCallback <TContext>(uint errorCode, uint numBytes, NativeOverlapped *overlap) { if (errorCode != 0) { Trace.TraceError("OverlappedStream GetQueuedCompletionStatus error: {0}", errorCode); } PageAsyncReadResult <TContext> result = (PageAsyncReadResult <TContext>)Overlapped.Unpack(overlap).AsyncResult; if (Interlocked.Decrement(ref result.count) == 1) { // We will be issuing another I/O, so free this overlap Overlapped.Free(overlap); long ptr = (long)pointers[result.page % BufferSize]; // Correct for page 0 of HLOG if (result.page == 0) { ptr += Constants.kFirstValidAddress; } long minObjAddress = long.MaxValue; long maxObjAddress = long.MinValue; while (ptr < (long)pointers[result.page % BufferSize] + PageSize) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key *key = Layout.GetKey(ptr); var addr = ((AddressInfo *)key)->Address; if (addr < minObjAddress) { minObjAddress = addr; } addr += ((AddressInfo *)key)->Size; if (addr > maxObjAddress) { maxObjAddress = addr; } } if (Value.HasObjectsToSerialize()) { Value *value = Layout.GetValue(ptr); var addr = ((AddressInfo *)value)->Address; if (addr < minObjAddress) { minObjAddress = addr; } addr += ((AddressInfo *)value)->Size; if (addr > maxObjAddress) { maxObjAddress = addr; } } } ptr += Layout.GetPhysicalSize(ptr); } // Object log fragment should be aligned by construction Debug.Assert(minObjAddress % sectorSize == 0); var to_read = (int)(maxObjAddress - minObjAddress); var objBuffer = ioBufferPool.Get(to_read); result.freeBuffer1 = objBuffer; var alignedLength = (to_read + (sectorSize - 1)) & ~(sectorSize - 1); // Request objects from objlog result.objlogDevice.ReadAsync( (int)(result.page >> (LogSegmentSizeBits - LogPageSizeBits)), (ulong)minObjAddress, (IntPtr)objBuffer.aligned_pointer, (uint)alignedLength, AsyncReadPageCallback <TContext>, result); } else { // Load objects from buffer into memory long ptr = (long)pointers[result.page % BufferSize]; // Correct for page 0 of HLOG if (result.page == 0) { ptr += Constants.kFirstValidAddress; } MemoryStream ms = new MemoryStream(result.freeBuffer1.buffer); ms.Seek(result.freeBuffer1.offset + result.freeBuffer1.valid_offset, SeekOrigin.Begin); while (ptr < (long)pointers[result.page % BufferSize] + PageSize) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key.Deserialize(Layout.GetKey(ptr), ms); } if (Value.HasObjectsToSerialize()) { Value.Deserialize(Layout.GetValue(ptr), ms); } } ptr += Layout.GetPhysicalSize(ptr); } ms.Dispose(); result.Free(); // Call the "real" page read callback result.callback(errorCode, numBytes, overlap); } }
private void WriteAsync <TContext>(IntPtr alignedSourceAddress, ulong alignedDestinationAddress, uint numBytesToWrite, IOCompletionCallback callback, PageAsyncFlushResult <TContext> asyncResult, IDevice device, ISegmentedDevice objlogDevice) { if (!Key.HasObjectsToSerialize() && !Value.HasObjectsToSerialize()) { device.WriteAsync(alignedSourceAddress, alignedDestinationAddress, numBytesToWrite, callback, asyncResult); return; } // need to write both page and object cache asyncResult.count++; MemoryStream ms = new MemoryStream(); var buffer = ioBufferPool.Get(PageSize); Buffer.MemoryCopy((void *)alignedSourceAddress, buffer.aligned_pointer, numBytesToWrite, numBytesToWrite); long ptr = (long)buffer.aligned_pointer; List <long> addr = new List <long>(); asyncResult.freeBuffer1 = buffer; // Correct for page 0 of HLOG if (alignedDestinationAddress >> LogPageSizeBits == 0) { ptr += Constants.kFirstValidAddress; } while (ptr < (long)buffer.aligned_pointer + numBytesToWrite) { if (!Layout.GetInfo(ptr)->Invalid) { long pos = ms.Position; Key *key = Layout.GetKey(ptr); Key.Serialize(key, ms); ((AddressInfo *)key)->IsDiskAddress = true; ((AddressInfo *)key)->Address = pos; ((AddressInfo *)key)->Size = (int)(ms.Position - pos); addr.Add((long)key); pos = ms.Position; Value *value = Layout.GetValue(ptr); Value.Serialize(value, ms); ((AddressInfo *)value)->IsDiskAddress = true; ((AddressInfo *)value)->Address = pos; ((AddressInfo *)value)->Size = (int)(ms.Position - pos); addr.Add((long)value); } ptr += Layout.GetPhysicalSize(ptr); } var s = ms.ToArray(); var objBuffer = ioBufferPool.Get(s.Length); asyncResult.freeBuffer2 = objBuffer; var alignedLength = (s.Length + (sectorSize - 1)) & ~(sectorSize - 1); var objAddr = Interlocked.Add(ref segmentOffsets[(alignedDestinationAddress >> LogSegmentSizeBits) % SegmentBufferSize], alignedLength) - alignedLength; fixed(void *src = s) Buffer.MemoryCopy(src, objBuffer.aligned_pointer, s.Length, s.Length); foreach (var address in addr) { *((long *)address) += objAddr; } objlogDevice.WriteAsync( (IntPtr)objBuffer.aligned_pointer, (int)(alignedDestinationAddress >> LogSegmentSizeBits), (ulong)objAddr, (uint)alignedLength, callback, asyncResult); device.WriteAsync((IntPtr)buffer.aligned_pointer, alignedDestinationAddress, numBytesToWrite, callback, asyncResult); }
/// <summary> /// Get location and range of object log addresses for specified log page /// </summary> /// <param name="ptr"></param> /// <param name="untilptr"></param> /// <param name="objectBlockSize"></param> /// <param name="startptr"></param> /// <param name="size"></param> public void GetObjectInfo(ref long ptr, long untilptr, int objectBlockSize, out long startptr, out long size) { long minObjAddress = long.MaxValue; long maxObjAddress = long.MinValue; while (ptr < untilptr) { if (!Layout.GetInfo(ptr)->Invalid) { if (Key.HasObjectsToSerialize()) { Key *key = Layout.GetKey(ptr); var addr = ((AddressInfo *)key)->Address; // If object pointer is greater than kObjectSize from starting object pointer if (minObjAddress != long.MaxValue && (addr - minObjAddress > objectBlockSize)) { break; } if (addr < minObjAddress) { minObjAddress = addr; } addr += ((AddressInfo *)key)->Size; if (addr > maxObjAddress) { maxObjAddress = addr; } } if (Value.HasObjectsToSerialize()) { Value *value = Layout.GetValue(ptr); var addr = ((AddressInfo *)value)->Address; // If object pointer is greater than kObjectSize from starting object pointer if (minObjAddress != long.MaxValue && (addr - minObjAddress > objectBlockSize)) { break; } if (addr < minObjAddress) { minObjAddress = addr; } addr += ((AddressInfo *)value)->Size; if (addr > maxObjAddress) { maxObjAddress = addr; } } } ptr += Layout.GetPhysicalSize(ptr); } // Handle the case where no objects are to be written if (minObjAddress == long.MaxValue && maxObjAddress == long.MinValue) { minObjAddress = 0; maxObjAddress = 0; } startptr = minObjAddress; size = maxObjAddress - minObjAddress; }