/// <summary> /// Finds the first free memarea with enough required contigous space. /// </summary> /// <param name="memRequirements">space requirements</param> /// <returns>null if no such area exists, i.e view is full</returns> private MemArena FindFirstFreeArena(uint memRequirements) { memRequirements += (uint)MemArena.Header.Size; MemArena arena = FirstArena(); if (arena.OffsetNext != 0) { arena.Capacity = (uint)(arena.OffsetNext - (arena.Offset + MemArena.Header.Size)); } if (_lastFreeArena != null) //save time .This improves performance by many times.. I am saving the last free arena, to be used for next instert. This eliminates list traversal for every add operation. { if (_lastFreeArena.IsFree && _lastFreeArena.Capacity >= memRequirements) { return(_lastFreeArena); } } while (arena != null) { if (arena.IsFree && arena.Capacity >= memRequirements) { return(arena); } arena = arena.NextArena(); } return(null); }
bool IEnumerator.MoveNext() { if (_view == null) { return(false); } _storage._viewManager.OpenView(_view); if (_arena == null) { _arena = _view.FirstArena(); } else { _arena = _arena.NextArena(); if (_arena == null) { _view = _storage._viewManager.GetViewByID(_view.ID + 1); if (_view != null) { _storage._viewManager.OpenView(_view); _arena = _view.FirstArena(); } } } return(_arena != null); }
public MemArena Allocate(uint size) { // Check if there isnt enough storage left in this view if (size > FreeSpace) { return(null); } MemArena arena = null; // Check if there isnt enough CONTIGOUS storage available // defragment the memory to create a large chunk of mem at // the end of view. size = MemArena.Content.RequiredSpace(size); arena = FindFirstFreeArena(size); if (arena == null) { CalculateArenaMemoryUsage(); //keep it here ..we need it. arena = DeFragment(); if (arena == null) { return(arena); } } /*if (size > MaxFreeSpace) //Now call to CalculateArenaMemoryUsage is avoided so lets call it ..if required. * { * arena = DeFragment(); * } * else * { * arena = FindFirstFreeArena(size); * } * if (arena == null) return arena;*/ // allocate space in parent arena. MemArena newArena = MemArena.SplitArena(arena, size); if (newArena == null) { return(arena); } arena.IsFree = false; if (arena != newArena) // deal with the case when splitarena returns the same arena back. Saves situation where allocated arena is accidently set to be free. { newArena.IsFree = true; _lastFreeArena = newArena; } FreeSpace = MyFreeSpace - (uint)MemArena.Header.Size; //CalculateArenaMemoryUsage(); removing it .... Usage++; return(arena); }
/// <summary> /// Swaps two arenas that are adjacent in view. /// </summary> internal static void SwapAdjacent(MemArena arena1, MemArena arena2) { arena1 = GetActualArena(arena1); arena2 = GetActualArena(arena2); // Only support swaping of adjacent aenas. if (!AreAdjacent(arena1, arena2)) { return; } // Determine arena order and cache settings! MemArena arenaLo = arena1, arenaHi = arena2; if (arena1.Offset > arena2.Offset) { arenaLo = arena2; arenaHi = arena1; } Header hdrLo = arenaLo.ArenaHeader; Header hdrHi = arenaHi.ArenaHeader; MemArena arenaHiNext = arenaHi.NextArena(); MemArena arenaLoPrev = arenaLo.PreviousArena(); arenaHiNext = GetActualArena(arenaHiNext); arenaLoPrev = GetActualArena(arenaLoPrev); // Swap memory contents of the arenas including headers! int loMemNeeded = arenaLo.IsFree ? Header.Size : (int)arenaLo.TotalLength; int hiMemNeeded = arenaHi.IsFree ? Header.Size : (int)arenaHi.TotalLength; byte[] arenaLoMem = arenaLo.RawView.Read((int)arenaLo.Offset, (int)loMemNeeded); byte[] arenaHiMem = arenaHi.RawView.Read((int)arenaHi.Offset, (int)hiMemNeeded); arenaHi._offset = arenaLo.Offset + arenaHi.TotalLength; arenaLo.RawView.Write(arenaHiMem, (int)arenaLo.Offset, (int)arenaHiMem.Length); arenaHi.RawView.Write(arenaLoMem, (int)arenaHi.Offset, (int)arenaLoMem.Length); // Fix up links and restore new settings! arenaLo.IsFree = hdrHi.IsFree; arenaLo.Capacity = hdrHi.Capacity; arenaLo.OffsetNext = arenaHi.Offset; arenaLo.OffsetPrev = hdrLo.OffsetPrev; SetPreviousArena(arenaLo, arenaLoPrev); // Fix up links and restore new settings! arenaHi.IsFree = hdrLo.IsFree; arenaHi.Capacity = hdrLo.Capacity; arenaHi.OffsetNext = hdrHi.OffsetNext; arenaHi.OffsetPrev = arenaLo.Offset; SetNextArena(arenaHi, arenaHiNext); }
public MmfObjectPtr Add(byte[] item) { if (item == null) { throw new ArgumentNullException("item"); } if (item.Length > _viewSize) { throw new ArgumentException("item size is larger than view size"); } // Find a view with enough space to contain the item. View view = _viewManager.GetMatchingView((uint)item.Length); try { if (view == null) { GrowMemoryMappedStore(1); view = _viewManager.GetMatchingView((uint)item.Length); } if (view != null) { MemArena arena = view.Allocate((uint)item.Length); if (arena == null) { return(null); } if (!arena.SetMemContents(item)) // It would return false only when size of Arena allocated is less then required even after all efforts to get arena of required size. { view.DeAllocate(arena); return(null); } return(new MmfObjectPtr(view, arena)); } } catch (OutOfMemoryException ex) { throw; } catch (Exception ex) { throw; } return(null); }
private static MemArena SetPreviousArena(MemArena arena, MemArena arenaPrev) { if (arenaPrev != null) //avoid scanario when two identical arenas are there for addition. { if (arenaPrev == arena) { return(arena); } } arena.OffsetPrev = arenaPrev == null ? 0 : arenaPrev.Offset; if (arenaPrev != null) { arenaPrev.OffsetNext = arena.Offset; } return(arena); }
/// <summary> /// Gets the primary allocated arena for the arena provided. Checks key and then gets the original one. /// </summary> // To keep the HashTable synch with the MemArena changes, we need to apply changes to only those objects that // are allocated primarily to be added into hash-table. This function returns the original allocated MemArena against a key // so that at time of MemArena updates _itemDict-->MmfObjectPtr-->MemArena is the one to be updated internal static MemArena GetActualArena(MemArena arenaCopy) { if (arenaCopy != null) { if (!arenaCopy.IsFree) { byte[] data = arenaCopy.GetMemContents(); StoreItem item = StoreItem.FromBinary(data, arenaCopy.View.ParentStorageProvider.CacheContext); MemArena arenAct = arenaCopy.View.ParentStorageProvider.GetMemArena(item.Key); return(arenAct); } else { return(arenaCopy); } } return(null); }
/// <summary> /// Creates and returns a Ptr to object. /// </summary> public MmfObjectPtr GetPtr(uint vid, uint offset) { View view = _viewManager.GetViewByID(vid); if (view == null) { return(null); } try { MemArena arena = view.ArenaAtOffset(offset); return(new MmfObjectPtr(view, arena)); } catch (Exception) { } return(null); }
/// <summary> /// Splits an arena into two adjacent arenas. Size of the first arena is equal /// to the size parameter. The second arenas occupies rest of the size of the /// parent arena. /// </summary> internal static MemArena SplitArena(MemArena arena, uint size) { uint sizeWithHeader = (uint)(size + Header.Size); if (arena.OffsetNext != 0) //Quick and dirty... { arena.Capacity = (uint)(arena.OffsetNext - (arena.Offset + Header.Size)); } if (sizeWithHeader > arena.Capacity) //size is replaced by sizeWithHeader... { return(null); } uint remainingCapacity = (uint)(arena.Capacity - size - Header.Size); //if value is negative .uint gived garbage. Reason for above change. // Check if the remaining space will be useful at all! // if not then there is no need to split and use the whole // arena instead. if (remainingCapacity < MemArena.SPLIT_THRESHOLD) { arena.View.MyFreeSpace -= (uint)(arena.Capacity + Header.Size); return(arena); } // Reduce parent arena's capacity. arena.Capacity = size; MemArena newArena = arena.View.ArenaAtOffset(arena.Offset + arena.TotalLength); newArena.Capacity = remainingCapacity; arena.View.MyFreeSpace -= (sizeWithHeader); // Fix up links! MemArena tempArena = arena.NextArena(); SetNextArena(newArena, GetActualArena(tempArena)); SetNextArena(arena, newArena); return(newArena); }
public override string ToString() { StringBuilder b = new StringBuilder(); b.Append("View, ID=").Append(ID) .Append(", maxFree=").Append(MaxFreeSpace) .Append(", Free=").Append(FreeSpace) .Append("\r\n"); if (IsOpen) { MemArena next = FirstArena(); while (next != null) { b.Append(next.ToString()).Append("\r\n"); next = next.NextArena(); } } return(b.ToString()); }
/// <summary> /// Formats the view and writes a valid header. Analogous to a /// hard-disk format operation. /// </summary> public void Format() { if (!IsOpen) { return; } int headerSize = ViewHeader.Size; Signature = ViewHeader.SIGNATURE; FreeSpace = MaxFreeSpace = (uint)(_view.Length - headerSize); MyFreeSpace = FreeSpace; _parentStorageProvider = null; MemArena arena = FirstArena(); arena.IsFree = true; arena.Capacity = (uint)(_view.Length - headerSize - MemArena.Header.Size); arena.OffsetNext = 0; arena.OffsetPrev = 0; }
public MemArena DeAllocate(MemArena arena) { if (arena.IsFree) { return(arena); } uint freedMem = arena.Capacity; arena.View.MyFreeSpace += arena.Capacity; arena.IsFree = true; arena = MemArena.CoalesceAdjacent(arena); arena.IsFree = true; FreeSpace = MyFreeSpace - (uint)MemArena.Header.Size; //CalculateArenaMemoryUsage(); removing it.. Usage++; return(arena); }
/// <summary> /// /// </summary> /// <returns></returns> public MemArena DeFragment() { MemArena lastArena = FirstArena(); do { MemArena current = lastArena.NextArena(); if (current == null) { break; } // If the last arena is used we dont need to swap it down. if (!lastArena.IsFree) { lastArena = current; continue; } // Two consecutive free arenas, rare, but taken care of! if (current.IsFree) { lastArena = MemArena.CoalesceAdjacent(current); } else { // A free arena followed by a used one so we swap down the free one. MemArena.SwapAdjacent(current, lastArena); lastArena = current; } }while (true); this.FreeSpace = lastArena.Capacity; this.MaxFreeSpace = lastArena.Capacity; CalculateArenaMemoryUsage(); //may be we need it here.. very low frequency of this to be called.. return(lastArena); }
private void CalculateArenaMemoryUsage() { MemArena arena = FirstArena(); MemArena firstArena = FirstArena(); //need to keep the first ..for avoiding circular linkages.. uint maxFree = 0; uint totalFree = 0; while (arena != null) { try { if (arena.IsFree) { totalFree += arena.Capacity; if (arena.Capacity >= maxFree) { maxFree = arena.Capacity; } } arena = arena.NextArena(); if (arena != null) { if (arena.OffsetNext == firstArena.Offset) { arena.OffsetNext = 0; } } } catch (Exception e) { throw new Exception(e.Message); } } this.FreeSpace = totalFree; this.MaxFreeSpace = maxFree; this.MyFreeSpace = this.FreeSpace + (uint)MemArena.Header.Size; }
public bool SetMemContents(byte[] value) { // capacity minus data-length minus data int diff = (int)(Capacity - Content.RequiredSpace((uint)value.Length)); if (diff >= 0) { Content item = new Content(); item.Data = value; item.RawWrite(RawView, (int)DataOffset); if (diff > SPLIT_THRESHOLD) { MemArena newArena = SplitArena(this, Content.RequiredSpace((uint)value.Length)); if (newArena != this) { newArena.IsFree = true; } } return(true); } return(false); }
public MmfStorageEnumerator(MmfStorage storage) { _storage = storage; _view = _storage._viewManager.GetViewByID(0); _arena = null; }
void IEnumerator.Reset() { _view = _storage._viewManager.GetViewByID(0); _arena = null; }
/// <summary> /// Coalesces/Merges all the adjacent FREE arenas into one arena. /// </summary> internal static MemArena CoalesceAdjacent(MemArena arena) { // Only free arenas can be coalesced. if (!arena.IsFree) { return(arena); } // Check if there is an arena next to this one. MemArena curr = arena; MemArena next = arena.NextArena(); int nHeaderCount = 0;//need to know how many headers are being freed while merging free arenas. if (next != null) { uint freedSpace = 0; // Find the first USED arena below this arena in the view. // Skip/Merge all the free arenas along the way. while (next != null && next.IsFree) { nHeaderCount++; freedSpace += next.TotalLength; curr = next; next = next.NextArena(); } // Fix up links! if (freedSpace > 0) { arena.Capacity += freedSpace; uint nCapacity = arena.Capacity; arena = SetNextArena(arena, GetActualArena(next)); //update only the actual arena arena.Capacity = nCapacity; } } if (arena.HasPrevious) { uint freedSpace = 0; // Find the first USED arena above this arena in the view. // Skip/Merge all the free arenas along the way. MemArena cur = arena; MemArena prev = null; do { prev = cur.PreviousArena(); if (prev == null || !prev.IsFree) { break; } freedSpace += prev.TotalLength; cur = prev; nHeaderCount++; }while (true); // Fix up links! For even if we find previous arena free.. The last from previous is now our Pivot.Its call to adjust its Next then. if (freedSpace > 0) { arena.Capacity += freedSpace; uint nCapacity = arena.Capacity; MemArena tempNext = arena.NextArena(); arena = SetNextArena(cur, GetActualArena(next)); //update only the actual arena arena.Capacity = nCapacity; } } if (nHeaderCount > 0) //update memory freed, while merging arenas. { arena.View.MyFreeSpace += (uint)(nHeaderCount * Header.Size); } return(arena); }
/// <summary> /// Returns true if the specified arenas are adjacent in the view. /// </summary> private static bool AreAdjacent(MemArena arena1, MemArena arena2) { return(arena1.OffsetNext == arena2.Offset || arena2.OffsetNext == arena1.Offset); }