/// <summary> /// Shrink space /// </summary> internal void ShrinkObject(VSObject o, long new_size) { if (o.Chunk == 1) { long current_size = o.Size; VSAllocation a = o.LastChunk; while ((current_size - a.Length) >= new_size) { VSAllocation prev_alloc = a.PrevChunk; if (prev_alloc.Chunk == 1) // 1st segment { o.LAST = 0; o.Chunk = 0; } else { o.LAST = prev_alloc.DescriptorAddress; prev_alloc.Chunk = (short)(prev_alloc.Chunk * (-1)); } current_size -= a.Length; o.SetSize(current_size); FreeSpaceSegment(a, false); a = prev_alloc; } } }
/// <summary> /// Free space by allocation address (protected) /// </summary> internal void Free(VSAllocation a, bool deleteID = true) { VSAllocation nxt = null; if (a.Chunk != 0) { nxt = GetAllocationByDescriptor(a.NEXT); } FreeSpaceSegment(a, deleteID); while (nxt != null) { long nextAddr = nxt.NEXT; short ch = nxt.Chunk; FreeSpaceSegment(nxt, false); if ((nextAddr > 0) & (ch > 0)) { nxt = GetAllocationByDescriptor(nextAddr); } else { nxt = null; } } }
/************************************************************************************/ /************************ Space management *************************************/ /************************************************************************************/ /************************************************************************************/ /****************** Protected space management (system methods) *******************/ /************************************************************************************/ /// <summary> /// Allocate space /// </summary> /// <param name="size"></param> /// <param name="pool"></param> /// <param name="generateID"></param> /// <returns></returns> internal VSAllocation ALLOCATE_SPACE(long size, short pool, bool generateID = true, long chunk = 0, short fixed_size = 0) { long ch = size; long s = 0; if (chunk > 0) { ch = chunk; } VSAllocation a = AllocateSpaceSegment(ch, pool, generateID); a.FIXED = (ushort)fixed_size; a.ChunkSize = (int)chunk; s += ch; while (s < size) { long a_size = (ch > (size - s)) ? (size - s) : ch; AllocateSpaceSegment(a_size, 0, false, a); s += a_size; } return(a); }
/// <summary> /// Update refrence by Key /// </summary> /// <param name="key"></param> /// <returns></returns> public void Update(long key, VSAllocation a) { long[] ret = this.SearchKey(key); if (ret[2] >= 0) { KeyBlockAllocWrite.Write((ret[2] * KeyBlockDef.BLOCK_ITEM_LENGTH) + KeyBlockDef.A_Address, a.DescriptorAddress); } }
/// <summary> /// Delete this node and free space /// </summary> public bool Delete() { //VSDebug.StopPoint(this.ID, 41); bool root_deleted = ((PARENT == 0) & (LEFT == 0) & (RIGHT == 0)); sp.Free(ALLOCATION); ALLOCATION = null; return(root_deleted); }
/// <summary> /// Initialize data structures /// </summary> private void Initialize() { KeyHeader = new KeyHeaderDef(); // Get root allocation KeyHeaderAlloc = sp.GetRootAllocation(DEFS.POOL_KEY); // If ROOT doesn't exist yet - initial allocation if (KeyHeaderAlloc == null) { // Allocate header space KeyHeaderAlloc = sp.AllocateSpace(KeyHeaderDef.KEYROOT_SIZE, DEFS.POOL_KEY, generateID: false); KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLast, -1); // Allocate descriptor space KeyDescriptorAlloc = sp.AllocateSpace(KeyDescriptorDef.DESCRIPTOR_CHUNK_SIZE, DEFS.POOL_KEY, generateID: false); //Set initial values to memory object KeyHeader.DescriptorAddress = KeyDescriptorAlloc.DescriptorAddress; KeyHeader.DescriptorLength = KeyDescriptorDef.DESCRIPTOR_CHUNK_LENGTH; KeyHeader.DescriptorLast = -1; KeyHeader.DescriptorUsed = 0; KeyHeader.LastKey = 0; // Save initial values KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorAddress, KeyHeader.DescriptorAddress); KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLength, KeyHeader.DescriptorLength); KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLast, KeyHeader.DescriptorLast); KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorUsed, KeyHeader.DescriptorUsed); KeyHeaderAlloc.Write(KeyHeaderDef.A_LastKey, KeyHeader.LastKey); // Create descriptor KeyDescriptor = new KeyDescriptorDef[KeyHeader.DescriptorLength]; } else { // Read header KeyHeader.DescriptorAddress = KeyHeaderAlloc.ReadLong(KeyHeaderDef.A_DescriptorAddress); KeyHeader.DescriptorLength = KeyHeaderAlloc.ReadInt(KeyHeaderDef.A_DescriptorLength); KeyHeader.DescriptorLast = KeyHeaderAlloc.ReadInt(KeyHeaderDef.A_DescriptorLast); KeyHeader.DescriptorUsed = KeyHeaderAlloc.ReadInt(KeyHeaderDef.A_DescriptorUsed); KeyHeader.LastKey = KeyHeaderAlloc.ReadLong(KeyHeaderDef.A_LastKey); // Read descriptor KeyDescriptor = new KeyDescriptorDef[KeyHeader.DescriptorLength]; KeyDescriptorAlloc = sp.GetAllocationByDescriptor(KeyHeader.DescriptorAddress); for (int i = 0; i < KeyHeader.DescriptorLength; i++) { KeyDescriptor[i].Address = KeyDescriptorAlloc.ReadLong((KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH * i) + KeyDescriptorDef.A_Address); KeyDescriptor[i].FirstKey = KeyDescriptorAlloc.ReadLong((KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH * i) + KeyDescriptorDef.A_FirstKey); KeyDescriptor[i].Used = KeyDescriptorAlloc.ReadInt((KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH * i) + KeyDescriptorDef.A_Used); } } }
/// <summary> /// Roll Changes (create FBQE for new space, process new allocation) /// Call from VSEngine when 'Open' or after extesion /// </summary> internal void VerifySpaceChanges() { FreeSpaceMgr = new VSFreeSpaceManager(this); // Process new allocations if exists short n_new = vm.ReadShort(DEFS.SYSTEM_ALLOCATION_ADDRESS); if (n_new > 0) { long e_address = DEFS.SYSTEM_ALLOCATION_ADDRESS + 2; for (int i = 0; i < n_new; i++) { long fstart = vm.ReadLong(e_address); long fend = vm.ReadLong(e_address + 8); if (FreeSpaceMgr.LAST < 0) { FreeSpaceMgr.AddFBQE(fstart, fend - fstart, FreeSpaceMgr.LAST, -1); } else { VSFreeSpaceManager.FBQE fp = FreeSpaceMgr.GetFBQE(FreeSpaceMgr.LAST); if (fp.ADDRESS_END == fstart) //Extend last FBQE { FreeSpaceMgr.UpdateFBQE(FreeSpaceMgr.LAST, fp.ADDRESS_START, fp.LENGTH + fend - fstart); } else { FreeSpaceMgr.AddFBQE(fstart, fend - fstart, FreeSpaceMgr.LAST, -1); } } e_address += 16; } // Cleanup allocation table vm.Write(DEFS.SYSTEM_ALLOCATION_ADDRESS, (short)0); // Expand FBQE block if needed FreeSpaceMgr.CheckFreeQueueSize(); } //Initialize KeyHelper key_manager = new VSKeyManager(this); //Check pool areas descriptors, create if nulls A_POOL_USER_DEFINED = GetRootAllocation(DEFS.POOL_USER_DEFINED); if (A_POOL_USER_DEFINED == null) { A_POOL_USER_DEFINED = AllocateSpace(DEFS.ALLOCATION_USER_DEFINED, DEFS.POOL_USER_DEFINED, false, 0); } A_POOL_DYNAMIC = GetRootAllocation(DEFS.POOL_DYNAMIC); if (A_POOL_DYNAMIC == null) { A_POOL_DYNAMIC = AllocateSpace(DEFS.ALLOCATION_DYNAMIC, DEFS.POOL_DYNAMIC, false, 0); } }
/// <summary> /// Free space by ID /// </summary> /// <param name="id"></param> /// <returns></returns> public int ReleaseID(long id) { VSAllocation a = GetAllocation(id); if (a == null) { return(-1); } Free(a); return(0); }
/// <summary> /// Return index of the descriptor item of -1 - not found /// </summary> /// <param name="key"></param> /// <returns> /// ret[0] - object address (if found); -1 - not found; /// ret[1] - descriptor index (if found) /// ret[2] - block index (if found) /// </returns> private long[] SearchKey(long key) { long[] ret = new long[3]; ret[0] = -1; ret[1] = -1; ret[2] = -1; long lastk = 0; // 1. Check last used block if (KeyBlockReadIndex >= 0) // Not 1st search { lastk = KeyDescriptor[KeyBlockReadIndex].FirstKey + KeyBlockDef.BLOCK_LENGTH - 1; // Last key in block if ((key < KeyDescriptor[KeyBlockReadIndex].FirstKey) | (key > lastk)) { KeyBlockReadIndex = -1; } } // 2. No last used - find descriptor if (KeyBlockReadIndex < 0) { for (int i = KeyHeader.DescriptorLast; i >= 0; i--) { if (KeyDescriptor[i].Used > 0) { lastk = KeyDescriptor[i].FirstKey + KeyBlockDef.BLOCK_LENGTH - 1; // Last key in block if ((key >= KeyDescriptor[i].FirstKey) & (key <= lastk)) { KeyBlockReadIndex = i; break; } } } } // 3. Descriptor found - check if key is allocated if (KeyBlockReadIndex >= 0) { KeyBlockAllocWrite = sp.GetAllocationByDescriptor(KeyDescriptor[KeyBlockReadIndex].Address); long obj_index = key - KeyDescriptor[KeyBlockReadIndex].FirstKey; long addr = (obj_index * KeyBlockDef.BLOCK_ITEM_LENGTH) + KeyBlockDef.A_Address; long obj_addr = KeyBlockAllocWrite.ReadLong(addr); if (obj_addr >= 0) { ret[0] = obj_addr; ret[1] = KeyBlockReadIndex; ret[2] = obj_index; } } // Assuming KeyBlockAlloc is loaded if ret[0] >= 0 return(ret); }
/// <summary> /// Create object /// </summary> /// <param name="size"></param> /// <param name="pool"></param> /// <param name="chunk"></param> /// <returns></returns> public VSObject Allocate(long size, short pool, long chunk = 0, short fixed_size = 0) { // Cannot be a system pool (0 or less) if (pool < 1) { throw new VSException(DEFS.E0012_INVALID_POOL_NUMBER_CODE, "- " + pool.ToString() + " (Allocate)"); } VSAllocation a = ALLOCATE_SPACE(size, pool, true, chunk, fixed_size); return(GetObject(a.Id)); }
/////////////////////////////////////////////////////////////////// /////////// METHODS ////// ///////////////////////////////////// /////////////////////////////////////////////////////////////////// /// <summary> /// Read node /// </summary> /// <param name="id"></param> public void Read(long id) { //VSDebug.StopPoint(id, 1323); ALLOCATION = sp.GetAllocation(id); string s = ALLOCATION.ReadString(0, 4); if (s != DEFS.AVL_SIGNATURE) { throw new VSException(DEFS.E0006_INVALID_SIGNATURE_CODE, "- VSAVL, at address 0x" + ALLOCATION.Address.ToString("X")); } }
/// <summary> /// Constructor - read index descriptor /// </summary> /// <param name="s"></param> /// <param name="addr"></param> internal VSIndex(VSpace space, long addr) { this.sp = space; this.ALLOCATION = sp.GetAllocationByDescriptor(addr); string s = ALLOCATION.ReadString(0, 4); if (s != DEFS.INDEX_SIGNATURE) { throw new VSException(DEFS.E0006_INVALID_SIGNATURE_CODE, " (Index Descriptor)"); } this.space_name = DEFS.ParseIndexSpace(this.Name); this.index_name = DEFS.ParseIndexName(this.Name); }
/// <summary> /// Delete index /// </summary> internal void purge() { if (ALLOCATION == null) { return; } // Delete all cross-references if (POOL > 0) { sp.ReleasePool(POOL); // Delete all nodes } sp.Free(ALLOCATION); // Delete descriptor ALLOCATION = null; }
/// <summary> /// Free all pool data /// </summary> /// <param name="n"></param> public void ReleasePool(short n) { if (n < 1) { throw new VSException(DEFS.E0014_INVALID_POOL_NUMBER_CODE, "- " + n.ToString()); } long addr = GetRootAddress(n); while (addr > 0) { VSAllocation a = GetAllocationByDescriptor(addr); addr = a.NEXT; FreeSpaceSegment(a); addr = GetRootAddress(n); } }
/// <summary> /// Constructor - create index descriptor /// </summary> /// <param name="s"></param> /// <param name="name"></param> /// <param name="unique"></param> internal VSIndex(VSpace space, string name, bool unique) { this.sp = space; this.ALLOCATION = sp.AllocateSpace(VSIndex.INDEX_DESCRIPTOR_LEN, DEFS.POOL_INDEX, true); this.ALLOCATION.Write(0, DEFS.INDEX_SIGNATURE); this.Name = name.Trim().ToLower(); this.ROOT = 0; this.POOL = 0; this.UNIQUE = (short)(unique ? 1 : 0); this.space_name = DEFS.ParseIndexSpace(this.Name); this.index_name = DEFS.ParseIndexName(this.Name); }
/// <summary> /// Create new node /// </summary> /// <returns>id</returns> public long Create(byte[] key, long value, long parent, short pool) { long base_size = VARIABLE_POS + key.Length + 8; long alloc_size = (ix.UniqueIndex) ? base_size : DEFS.MIN_SPACE_ALLOCATION_CHUNK * 2; this.ALLOCATION = sp.AllocateSpace(alloc_size, pool); this.SG = DEFS.AVL_SIGNATURE; this.REF_COUNT = 1; this.KEYLEN = key.Length; this.ALLOCATION.Write(KEY_POS, key, key.Length); this.PARENT = parent; this.INDEX = ix.Id; // Index Id this.REF = value; // 1st ref value return(ID); }
public VSFreeSpaceManager(VSpace _sp) { Space = _sp; vm = Space.VM; long hdr_address = Space.GetFirstAddress(DEFS.POOL_FREE_SPACE); if (hdr_address == 0) { // Initialization // 1. Create H-block (header) H_Object = new VSAllocation(vm, DEFS.FBQE_HEADER_ADDRESS, DEFS.FBQE_HEADER_LENGTH_FULL, 0); H_Object.Write(0, DEFS.FBQE_HEADER_SIGNATURE); this.MAX = DEFS.FBQE_ALLOCATION_NUMBER; // Max number of FBQE this.FREE = MAX; this.FIRST = -1; this.LAST = -1; this.FIRST_Q = 0; this.LAST_Q = FREE - 1; // 2. Save H-block address (1st object) Space.SetFirstAddress(DEFS.POOL_FREE_SPACE, H_Object.DescriptorAddress); // 1st object // 3. Create 1st FBQE block F_Object = new VSAllocation(vm, H_Object.DescriptorAddress + H_Object.FullLength, (DEFS.FBQE_ALLOCATION_LENGTH + DEFS.BaseDescriptorLength), 0); // 4. Set initial size F_Object.SetSize(DEFS.FBQE_ALLOCATION_LENGTH); buffer = new byte[F_Object.Size]; // Create buffer // 5. Set references F_Object.PREV = H_Object.DescriptorAddress; H_Object.NEXT = F_Object.DescriptorAddress; // Address of the 1st block F-block // 6. Save F-block address (last object) Space.SetLastAddress(DEFS.POOL_FREE_SPACE, F_Object.DescriptorAddress); //last object // 1.3 Initiate Free queue for (int i = 0; i < FREE; i++) { CreateFBQE(i); } BuildBTrees(); // 1.4 Create initial FBQE long fa = F_Object.DescriptorAddress + F_Object.FullLength; // 1st free address AddFBQE(fa, (Space.vm.Size - fa), -1, -1); // Create 1st FBQE } else { H_Object = Space.GetAllocationByDescriptor(hdr_address); F_Object = Space.GetAllocationByDescriptor(H_Object.NEXT); byte[] b = H_Object.ReadBytes(0, FBQE_HEADER_LENGTH); this.v_MAX = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, MAX_POS, MAX_LEN)); this.v_FREE = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, FREE_POS, FREE_LEN)); this.v_FIRST = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, FIRST_POS, FIRST_LEN)); this.v_LAST = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, LAST_POS, LAST_LEN)); this.v_FIRST_Q = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, FIRST_Q_POS, FIRST_Q_LEN)); this.v_LAST_Q = VSLib.ConvertByteToInt(VSLib.GetByteArray(b, LAST_Q_POS, LAST_Q_LEN)); buffer = F_Object.ReadBytes(0, F_Object.Size); // Read buffer BuildBTrees(); } }
/// <summary> /// Create new KEY for address /// If use_key > 0 then add specified key (used by restore) /// If alloc=null - add 0 address (restore) /// </summary> /// <returns>new SID</returns> public long Add(VSAllocation alloc, long use_key = 0) { //VSDebug.StopPoint(alloc.Address, 45724); long address = (alloc == null) ? 0 : alloc.DescriptorAddress; long addr = 0; // 1. Generate new key if (use_key > 0) { if (use_key <= KeyHeader.LastKey) { throw new VSException(DEFS.E0023_INVALID_KEY_SEQUENCE_CODE, " Lask key: " + KeyHeader.LastKey.ToString() + " Use key: " + use_key.ToString()); } KeyHeader.LastKey = use_key; } else { KeyHeader.LastKey++; } // Write new key KeyHeaderAlloc.Write(KeyHeaderDef.A_LastKey, KeyHeader.LastKey); // Lookup place to add KeyBlockAllocWrite = null; if (KeyHeader.DescriptorLast >= 0) { if (KeyHeader.LastKey < (KeyDescriptor[KeyHeader.DescriptorLast].FirstKey + KeyBlockDef.BLOCK_LENGTH)) { KeyBlockAllocWrite = sp.GetAllocationByDescriptor(KeyDescriptor[KeyHeader.DescriptorLast].Address); } } // Not found, allocate new block if (KeyBlockAllocWrite == null) { KeyBlockAllocWrite = sp.AllocateSpace(KeyBlockDef.BLOCK_SIZE, DEFS.POOL_KEY, generateID: false); byte[] b = new byte[KeyBlockDef.BLOCK_SIZE]; // Fill all by -1 for (int i = 0; i < KeyBlockDef.BLOCK_SIZE; i++) { b[i] = 255; } KeyBlockAllocWrite.Write(0, b, b.Length); KeyHeader.DescriptorLast++; KeyHeader.DescriptorUsed++; KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLast, KeyHeader.DescriptorLast); KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorUsed, KeyHeader.DescriptorUsed); // Extend if required if (KeyHeader.DescriptorLast == KeyHeader.DescriptorLength) { sp.Extend(KeyHeaderAlloc, KeyDescriptorDef.DESCRIPTOR_CHUNK_SIZE); KeyHeader.DescriptorLength += KeyDescriptorDef.DESCRIPTOR_CHUNK_LENGTH; KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLength, KeyHeader.DescriptorLength); } KeyDescriptor[KeyHeader.DescriptorLast].FirstKey = KeyHeader.LastKey; KeyDescriptor[KeyHeader.DescriptorLast].Address = KeyBlockAllocWrite.DescriptorAddress; KeyDescriptor[KeyHeader.DescriptorLast].Used = 0; addr = KeyHeader.DescriptorLast * KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH; KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Address, KeyDescriptor[KeyHeader.DescriptorLast].Address); KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_FirstKey, KeyDescriptor[KeyHeader.DescriptorLast].FirstKey); } // Write to block KeyBlockAllocWrite = sp.GetAllocationByDescriptor(KeyDescriptor[KeyHeader.DescriptorLast].Address); addr = ((KeyHeader.LastKey - KeyDescriptor[KeyHeader.DescriptorLast].FirstKey) * KeyBlockDef.BLOCK_ITEM_LENGTH); KeyBlockAllocWrite.Write(addr + KeyBlockDef.A_Address, address); // Update used KeyDescriptor[KeyHeader.DescriptorLast].Used++; KeyDescriptorAlloc.Write((KeyHeader.DescriptorLast * KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH) + KeyDescriptorDef.A_Used, KeyDescriptor[KeyHeader.DescriptorLast].Used); // Set read cache KeyBlockAllocRead = KeyBlockAllocWrite; KeyBlockReadIndex = KeyHeader.DescriptorLast; // Return key return(KeyHeader.LastKey); }
//////////////////////////////////////////////////////////////////////////////// //////////////////// I/O METHODS /////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// /// <summary> /// Read/Write bytes /// </summary> /// <param name="op">DEFS.OP_READ or DEFS.OP_WRITE</param> /// <param name="address"></param> /// <param name="data"></param> /// <param name="length"></param> /// <returns></returns> protected void io_protected(int op, long address, ref byte[] data, long length) { if (length <= 0) { throw new VSException(DEFS.E0028_INVALID_LENGTH_ERROR_CODE, "- " + length.ToString()); } long r_length = length; // Remaining length long s_address = 0; // Shifted address VSAllocation obj = this; bool eo_chunk = false; if (address < this.Length) { s_address = 0; // Address is in the current chunk } else { // Search cache obj = null; for (int i = (SCache.Count - 1); i >= 0; i--) { if ((address >= SCache[i].VIRTUAL_ADDRESS) & (address < (SCache[i].VIRTUAL_ADDRESS + SCache[i].LENGTH))) { s_address = SCache[i].VIRTUAL_ADDRESS; obj = new VSAllocation(vm, SCache[i].DESCRIPTOR_ADDRESS); break; } } if (obj == null) { // NOT found in cache if ((this.Chunk == 0) | (this.NEXT == 0)) { eo_chunk = true; } else { obj = this.NextChunk; s_address = this.Length; while (!eo_chunk) { if (address < (s_address + obj.Length)) { // Address is in chunk, add to cache if (SCache.Count == cache_size) { SCache.RemoveAt(0); } SegmentCache ac = new SegmentCache(); ac.VIRTUAL_ADDRESS = s_address; ac.LENGTH = obj.Length; ac.DESCRIPTOR_ADDRESS = obj.DescriptorAddress; SCache.Add(ac); break; } else { //start address not in this chunk if ((obj.Chunk > 0) & (obj.NEXT > 0)) { s_address += obj.Length; obj = obj.NextChunk; } else { eo_chunk = true; } } } } } } if (obj != null) { long l_address = address - s_address; // Local address in chunk long r_address = 0; // Relative address in the input array while ((obj != null) & (r_length > 0) & !eo_chunk) { long l_length = (r_length > (obj.Length - l_address)) ? (obj.Length - l_address) : r_length; vm.Io(obj.Address + l_address, ref data, l_length, op, r_address); l_address = 0; r_length -= l_length; r_address += l_length; obj = obj.NextChunk; } } if ((r_length > 0) | (length <= 0) | (address < 0)) { throw new VSException(DEFS.E0019_INVALID_OP_ADDRESS_ERROR_CODE, "- address " + address.ToString() + "; lenght " + length.ToString()); } }
/// <summary> /// Delete existing ID /// </summary> /// <param name="sid"></param> public int Delete(long key) { // Get key long[] keyloc = SearchKey(key); if (keyloc[0] == 0) { return(-1); } // Delete key in the block long addr = keyloc[2] * KeyBlockDef.BLOCK_ITEM_LENGTH; KeyBlockAllocWrite.Write(addr + KeyBlockDef.A_Address, KeyBlockDef.KEY_DELETED); // Update descriptor (not last key) if (KeyDescriptor[keyloc[1]].Used > 1) { KeyDescriptor[keyloc[1]].Used--; addr = keyloc[1] * KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH; KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Used, KeyDescriptor[keyloc[1]].Used); } // If last key in the block - free block else { KeyBlockReadIndex = -1; KeyBlockAllocRead = null; sp.Free(KeyBlockAllocWrite, false); KeyDescriptor[keyloc[1]].Used = 0; KeyDescriptor[keyloc[1]].Address = 0; KeyDescriptor[keyloc[1]].FirstKey = 0; addr = keyloc[1] * KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH; KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Used, KeyDescriptor[keyloc[1]].Used); KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Address, KeyDescriptor[keyloc[1]].Address); KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_FirstKey, KeyDescriptor[keyloc[1]].FirstKey); KeyHeader.DescriptorUsed--; KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorUsed, KeyHeader.DescriptorUsed); for (int i = 0; i < KeyHeader.DescriptorLength; i++) { if (KeyDescriptor[i].Address == 0) { for (int j = i + 1; j < KeyHeader.DescriptorLength; j++) { if (KeyDescriptor[j].Address != 0) { KeyDescriptor[i].Address = KeyDescriptor[j].Address; KeyDescriptor[i].FirstKey = KeyDescriptor[j].FirstKey; KeyDescriptor[i].Used = KeyDescriptor[j].Used; KeyDescriptor[j].Address = 0; KeyDescriptor[j].FirstKey = 0; KeyDescriptor[j].Used = 0; break; } } } } // Update header last int save_last = KeyHeader.DescriptorLast; KeyHeader.DescriptorLast = KeyHeader.DescriptorUsed - 1; KeyHeaderAlloc.Write(KeyHeaderDef.A_DescriptorLast, KeyHeader.DescriptorLast); // Rewrite header for (int i = 0; i <= save_last; i++) { addr = i * KeyDescriptorDef.DESCRIPTOR_ITEM_LENGTH; KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Address, KeyDescriptor[i].Address); KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_FirstKey, KeyDescriptor[i].FirstKey); KeyDescriptorAlloc.Write(addr + KeyDescriptorDef.A_Used, KeyDescriptor[i].Used); } } return(0); }
/// <summary> /// Free space /// </summary> /// <param name="address"></param> /// <param name="length"></param> /// <returns></returns> private int FreeSpaceSegment(VSAllocation a, bool deleteID = true) { long a_prev = a.PREV; long a_next = a.NEXT; short a_pool = a.Pool; long a_id = a.Id; // Delete indexes if (deleteID & (a_id > 0) & (a_pool > 0)) { if (this.IndexSpace == null) { remove_all_indexes("", a_id); // Remove all local indexes } else { this.IndexSpace.remove_all_indexes(this.Name, a_id); // Remove all external indexes } } long address = a.DescriptorAddress; long length = a.FullLength; long end_address = address + length; if (end_address > this.vm.Size) { throw new VSException(DEFS.E0015_INVALID_ADDRESS_CODE, "Address is out of space boundaries - " + address.ToString()); } // Delete index if required if (deleteID & (a_id > 0)) { key_manager.Delete(a_id); } // return space to free and purge it // VSDebug.StopPoint(address, 57916); FreeSpaceMgr.ReleaseSpace(address, length); //Update descriptors //Ref to prev if (a_prev == 0) { SetFirstAddress(a_pool, a_next); } else { VSAllocation p = GetAllocationByDescriptor(a_prev); p.NEXT = a_next; } //Ref to next if (a_next == 0) { SetLastAddress(a_pool, a_prev); } else { VSAllocation n = GetAllocationByDescriptor(a_next); n.PREV = a_prev; } return(0); }
/// <summary> /// Get the 1st key /// </summary> /// <returns></returns> public long GetRootID(short pool) { VSAllocation a = GetAllocationByDescriptor(GetFirstAddress(pool)); return((a == null) ? 0 : a.Id); }
/************************************************************************************/ /************************ Memory management (system methods)***********************/ /************************************************************************************/ /// <summary> /// Allocate space (system method) /// </summary> /// <param name="size">Allocation size</param> /// <param name="pool">Allocation pool. 0 if base_address != 0</param> /// <param name="generateID">True id ID is required. false if base_address != 0</param> /// <param name="base_address"> 1st allocated address (extend)</param> /// <returns> /// 0 - address /// 1 - ID (or 0) /// </returns> internal VSAllocation AllocateSpaceSegment(long size, short pool, bool generateID = true, VSAllocation base_alloc = null) { #if (DEBUG) __TIMER.START("alloc:main"); #endif if ((base_alloc != null) & ((pool != 0) | (generateID == true))) { throw new VSException(DEFS.E0020_INVALID_EXTENSION_PARAMETERS_ERROR_CODE); } //VSFreeSpaceManager.FBQE f; long alloc_addr = 0; long length_desc = (base_alloc == null)? DEFS.BaseDescriptorLength: DEFS.ExpansionDescriptorLength; // Descriptor length // Calculate allocation size) long length = size / DEFS.MIN_SPACE_ALLOCATION_CHUNK; if (length == 0) { length++; } else if ((length * DEFS.MIN_SPACE_ALLOCATION_CHUNK) < size) { length++; } long length_use = (length * DEFS.MIN_SPACE_ALLOCATION_CHUNK); length = length_use + length_desc; // Acquire free space location alloc_addr = FreeSpaceMgr.AcquireSpace(length); while (alloc_addr == 0) { if (vm.Extend() != 0) { throw new VSException(DEFS.E0013_SPACE_NOT_AVAILABLE_CODE, "Requested size: " + length.ToString()); } else { this.VerifySpaceChanges(); //Process new if space is successfully extended } alloc_addr = FreeSpaceMgr.AcquireSpace(length); } short new_pool = pool; // If base_address != 0 - take pool# from the root descriptor if (base_alloc != null) { new_pool = base_alloc.Pool; } // Create allocated space descriptor VSAllocation new_obj = new VSAllocation(vm, alloc_addr, length, new_pool); long last_obj = GetLastAddress(new_pool); VSAllocation prev_obj; if (base_alloc == null) { // Initial allocation #if (DEBUG) __TIMER.START("alloc:new_alloc"); #endif #if (DEBUG) __TIMER.START("alloc:gen_id"); #endif if (generateID) { new_obj.Id = key_manager.Add(new_obj); // Generate ID if required } #if (DEBUG) __TIMER.END("alloc:gen_id"); #endif if (last_obj == 0) { // First allocation for pool SetFirstAddress(new_pool, alloc_addr); SetLastAddress(new_pool, alloc_addr); } else { prev_obj = GetAllocationByDescriptor(last_obj); prev_obj.NEXT = new_obj.DescriptorAddress; new_obj.PREV = prev_obj.DescriptorAddress; SetLastAddress(new_pool, new_obj.DescriptorAddress); // New Last } #if (DEBUG) __TIMER.END("alloc:new_alloc"); #endif } else { //Extend #if (DEBUG) __TIMER.START("alloc:extend_obj"); #endif prev_obj = base_alloc; if (base_alloc.Chunk == 0) { base_alloc.Chunk = 1; new_obj.Chunk = -2; } else { prev_obj = GetAllocationByDescriptor(base_alloc.LAST); short ch = (short)(prev_obj.Chunk * -1); if (ch == DEFS.MAX_SPACE_ALLOCATION_CHUNKS) { throw new VSException(DEFS.E0021_MAX_ALLOCATION_CHUNKS_REACHED_CODE, "- " + DEFS.MAX_SPACE_ALLOCATION_CHUNKS.ToString()); } prev_obj.Chunk = ch; new_obj.Chunk = (short)((ch + 1) * -1); } base_alloc.LAST = new_obj.DescriptorAddress; // New pointer to last if (prev_obj.NEXT == 0) { prev_obj.NEXT = new_obj.DescriptorAddress; new_obj.PREV = prev_obj.DescriptorAddress; SetLastAddress(new_pool, new_obj.DescriptorAddress); // New last } else { VSAllocation next_obj = GetAllocationByDescriptor(prev_obj.NEXT); prev_obj.NEXT = new_obj.DescriptorAddress; new_obj.NEXT = next_obj.DescriptorAddress; new_obj.PREV = prev_obj.DescriptorAddress; next_obj.PREV = new_obj.DescriptorAddress; } #if (DEBUG) __TIMER.END("alloc:extend_obj"); #endif } if (base_alloc == null) { new_obj.SetSize(length_use); } else { base_alloc.SetSize(base_alloc.Size + length_use); } #if (DEBUG) __TIMER.END("alloc:main"); #endif return(new_obj); }
/************************************************************************************/ /************************ Memory management (system methods)***********************/ /************************************************************************************/ /// <summary> /// Extend space (protected) /// </summary> /// <param name="address">Data address to extend</param> /// <param name="size">Additional size to add if > 0. Otherwise - min space chunk</param> public void Extend(VSAllocation o, long size) { VSAllocation a = AllocateSpaceSegment(size, 0, false, o); }
/// <summary> /// Next node /// </summary> /// <returns></returns> public bool Next() { if (action == Action.End) { return(false); } current = -1; // Cases - assuming index is not empty (action !- Action.End) // 1. Initial: D_Current < 0 if (D_current < 0) { D_current = 0; // Set 1st desc B_current = -1; KeyBlockAllocWrite = null; n = 0; NUM = (KeyHeader.DescriptorLast + 1) * KeyBlockDef.BLOCK_LENGTH; // Total numeber of items in all blocks (including empty and deleted) } while (n < NUM) { if (KeyDescriptor[D_current].Used == 0) // If empty block { n += KeyBlockDef.BLOCK_LENGTH; D_current++; B_current = -1; } else { B_current++; if (B_current == KeyBlockDef.BLOCK_LENGTH) // Out of block { KeyBlockAllocWrite = null; D_current++; B_current = -1; } else // Within block { if (KeyBlockAllocWrite == null) { KeyBlockAllocWrite = sp.GetAllocationByDescriptor(KeyDescriptor[D_current].Address); } if (KeyBlockAllocWrite.ReadLong(B_current * KeyBlockDef.BLOCK_ITEM_LENGTH + KeyBlockDef.A_Address) > 0) { current = KeyDescriptor[D_current].FirstKey + B_current; n++; break; } else { n++; } } } } if (current < 0) { action = Action.End; return(false); } return(true); }
/// <summary> /// Extend space (protected) /// </summary> /// <param name="address">Data address to extend</param> /// <param name="size">Additional size to add if > 0. Otherwise - min space chunk</param> internal void ExtendSpace(VSAllocation o, long size) { VSAllocation a = AllocateSpaceSegment(size, 0, false, o); }
/// <summary> /// Dump storage /// Space name - 32 /// System area - 1024 /// Pool area - 4096 /// </summary> private void dump(VSIO IO, string name) { bool was_opened = false; uint e_code = IO.GetEncryption() ? e_code = DEFS.DATA_ENCRYPTED : e_code = DEFS.DATA_NOT_ENCRYPTED; if (state == DEFS.STATE_OPENED) { if (TA.Started) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- Dump (transaction is in progress)"); } was_opened = true; } else { Open(null); } string[] spaces = this.GetSpaceList(); bool encr = IO.GetEncryption(); IO.SetEncryption(false); IO.Write(0, e_code); // + 0 (4)Encryption indicator IO.SetEncryption(encr); IO.Write(-1, DEFS.DUMP_SIGNATURE_INCOMPLETE); // + 4 (4) Signature 'incomplete' IO.Write(-1, (int)0); // + 8 (4) CRC placeholder IO.Write(-1, (long)0); // +12 (8)Total length for (int sp_index = 0; sp_index < spaces.Length; sp_index++) { VSpace sp = GetSpace(spaces[sp_index]); VSVirtualMemoryManager vm = GetVM(spaces[sp_index]); if ((name == "") | (VSLib.Compare(name, sp.Name))) { long sp_hdr_pos = IO.GetPosition(); // Position for header(number of bytes) IO.Write(-1, (long)0); // Save space header IO.Write(-1, (short)sp.Name.Length); // Space neme length (short) IO.Write(-1, sp.Name); // Space name IO.Write(-1, (short)sp.Owner.Length); // Space owner length (short) IO.Write(-1, sp.Owner); // Space owner ////////////////////////////////////////////////////////////// // Save keys ////////////////////////////////////////////////////////////// IO.Write(-1, DEFS.DUMP_KEYS_SIGNATURE); // Start keys VSKeyManager kh = sp.KeyManager; kh.Reset(); while (kh.Next()) { long k = kh.Current; IO.Write(-1, k); } IO.Write(-1, (long)-1); // End keys // Save pool ares (starting from 2) short[] pools = sp.GetPoolsForDump(); // Create list of pools for (int i = 0; i < pools.Length; i++) { long a_desc = sp.GetFirstAddress(pools[i]); while (a_desc > 0) { VSAllocation a = sp.GetAllocationByDescriptor(a_desc); //////////// Save ADSC fields /////////// IO.Write(-1, a.Id); IO.Write(-1, a.Pool); IO.Write(-1, (a.Chunk == 0) ? a.Length : a.Size); // Memory size IO.Write(-1, a.ChunkSize); // Chunk sizeMemory size IO.Write(-1, a.ALLOC); // Alloc version (object) IO.Write(-1, a.FIXED); // Fixed part (object) //////////// Save data ////////////////// byte[] b = vm.ReadBytes(a.Address, a.Length); IO.Write(-1, ref b); a_desc = a.NEXT; if (a.Chunk != 0) { while (a_desc != 0) { a = sp.GetAllocationByDescriptor(a_desc); if ((a.Chunk == 0) | (a.Chunk == 1)) { break; } b = vm.ReadBytes(a.Address, a.Length); IO.Write(-1, ref b); a_desc = a.NEXT; } } } } long sp_count = IO.GetPosition() - sp_hdr_pos; // Calculate count long current_pos = IO.GetPosition(); // Save current position IO.Write(sp_hdr_pos, sp_count); // Write count to the header (incl hdr) IO.SetPosition(current_pos); // Restore position } } IO.Write(-1, (long)-1); // Write eof indicator IO.Write(12, (long)IO.GetLength()); // + 8 (8) - Total length IO.Flush(); uint c = IO.GetCRC32(12, -1); // calculate CRC32 IO.Write(8, c); // + 4 (4) - CRC32 IO.Write(4, DEFS.DUMP_SIGNATURE); // Signature 'complete' IO.Flush(); if (!was_opened) { Close(); } }