/// <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> /// Return allocated space to the free queue: update FBQE chain and trees /// </summary> /// <param name="address"></param> /// <param name="length"></param> public void ReleaseSpace(long address, long length) { //VSDebug.StopPoint(address, 3740160); CheckFreeQueueSize(); VSBBTree.BTResult res1 = BT_FBQE_Address.Find(address, VSBBTree.COND_LT); VSBBTree.BTResult res2; if (res1.Key < 0) // Update 1st or insert befor 1st - left not found { // Address is before 1st FBQE. Insert new before 1st or extend 1st (new start address) if (this.FIRST < 0) { AddFBQE(address, length, -1, this.FIRST); } else { FBQE f = GetFBQE(this.FIRST); if (f.ADDRESS_START == (address + length)) // Extend 1st FBQE { UpdateFBQE(this.FIRST, address, f.LENGTH + length); } else { AddFBQE(address, length, -1, this.FIRST); // Insert new FBQE at the top of the queue } } } else { res2 = BT_FBQE_Address.Find(address, VSBBTree.COND_GT); if (res2.Key < 0) // Extend last or append { FBQE f = GetFBQE(this.LAST); if (f.ADDRESS_END == address) // Extend last { UpdateFBQE(this.LAST, f.ADDRESS_START, f.LENGTH + length); // Extend } else { AddFBQE(address, length, this.LAST, -1); // Append FBQE } } else { FBQE f1 = GetFBQE((int)res1.Value); FBQE f2 = GetFBQE((int)res2.Value); if ((address > f1.ADDRESS_END) & ((address + length) < f2.ADDRESS_START)) { this.AddFBQE(address, length, f1.index, f2.index); //insert new between f1 and f2 } else // Otherwise merge with left, right or both { if ((address == f1.ADDRESS_END) & ((address + length) == f2.ADDRESS_START)) { // Merge all UpdateFBQE(f1.index, f1.ADDRESS_START, f1.LENGTH + f2.LENGTH + length); DeleteFBQE(f2.index); } else if (address == f1.ADDRESS_END) { // Merge with left (f1) UpdateFBQE(f1.index, f1.ADDRESS_START, f1.LENGTH + length); // Extend f1 (append) } else { // Merge with right (f2) UpdateFBQE(f2.index, address, f2.LENGTH + length); // Extend f2 (insert) } } } } //Clear memory byte[] b = new byte[length]; vm.Write(address, b, length); }
/// <summary> /// Set object full size - all chunks (descriptor length is NOT included)) /// </summary> /// <param name="s"></param> internal void SetSize(long s) { vm.Write(DescriptorAddress + SIZE_POS, s); }
/// <summary> /// Restore storage /// </summary> public void restore(VSIO IO, string name = "*") { byte[] buf; // Buffer // Check database state if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Restore' (storage is opened or undefined)"); } // Check if length not less than 16 if (IO.GetLength() < 32) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Restore - invalid source stream (wrong source length)"); } // Check encryption IO.SetEncryption(false); uint encr = IO.ReadUInt(0); IO.SetEncryption(encr == DEFS.DATA_ENCRYPTED); // Check signature string sig = IO.ReadString(-1, DEFS.DUMP_SIGNATURE.Length); if (sig != DEFS.DUMP_SIGNATURE) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Restore - invalid source stream (wrong signature)"); } // Check CRC uint old_crc = IO.ReadUInt(-1); uint new_crc = IO.GetCRC32(12, -1); // calculate CRC32 if (old_crc != new_crc) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Restore - invalid source stream (wrong CRC)"); } // Check source length vs saved long slen = IO.ReadLong(-1); if (IO.GetLength() != slen) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Restore - invalid source stream (wrong source length)"); } long save_pos = IO.GetPosition(); // +16 long cpos = save_pos; TRANSACTIONS_ON = false; Open(); TA.RollMode = true; long splen = IO.ReadLong(cpos); // Space length // Validate list of spaces while (splen > 0) { // Read space name length int n_len = IO.ReadShort(cpos + 8); // Read space name string sname = IO.ReadString(cpos + 10, n_len); VSpace sp = GetSpace(sname); if (sp == null) { this.Close(); this.Create(sname); this.Open(); } cpos += splen; splen = IO.ReadLong(cpos); } // Restore position IO.SetPosition(save_pos); // Proceed with restore splen = IO.ReadLong(-1); long spcnt = 8; while (splen != -1) { // Read space name length int n_len = IO.ReadShort(-1); // Read space name string sname = IO.ReadString(-1, n_len); spcnt += (n_len + 2); // Read owner length int o_len = IO.ReadShort(-1); // Read Owner string sowner = IO.ReadString(-1, o_len); spcnt += (o_len + 2); VSpace sp = GetSpace(sname); VSVirtualMemoryManager vm = GetVM(sname); sp.Owner = sowner; vm.Write(DEFS.SYSTEM_STATUS_ADDRESS, DateTime.Now.ToBinary()); // Write timestamp - restore started if (!IMO) { vm.flush(); } // Restore keys if (IO.GetPosition() < IO.GetLength()) { sig = IO.ReadString(-1, DEFS.DUMP_KEYS_SIGNATURE.Length); spcnt += DEFS.DUMP_KEYS_SIGNATURE.Length; if (sig != DEFS.DUMP_KEYS_SIGNATURE) { throw new VSException(DEFS.E0006_INVALID_SIGNATURE_CODE, "(Restore missing start key signature)"); } VSKeyManager kh = sp.KeyManager; if (!kh.IsEmpty) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Space '" + sname + "' is not empty. Restore terminated."); } long id = IO.ReadLong(-1); spcnt += 8; while (id >= 0) { //VSDebug.StopPoint(id, 23884); //VSDebug.StopPoint(id, 24033); kh.Add(null, id); id = IO.ReadLong(-1); spcnt += 8; } } // Restore data pools long size = 0; int chunk_size = 0; ushort alloc = 0; ushort fix = 0; while (spcnt < splen) { VSAllocation new_a; //Read ADSC fields long oldid = IO.ReadLong(-1); short pool = IO.ReadShort(-1); spcnt += 10; size = IO.ReadLong(-1); // Total size spcnt += 8; chunk_size = IO.ReadInt(-1); // Chunk size spcnt += 4; alloc = IO.ReadUShort(-1); // Alloc spcnt += 2; fix = IO.ReadUShort(-1); // Fixed part length spcnt += 2; buf = IO.ReadBytes(-1, (int)size); spcnt += size; // Allocate space new_a = sp.ALLOCATE_SPACE(size, pool, false, (long)chunk_size, (short)fix); new_a.ALLOC = (ushort)((alloc == 0) ? 0 : 1); // Set allocation 0 - RAW; 1 - FIELD if (oldid > 0) { new_a.Id = oldid; sp.KeyManager.Update(oldid, new_a); } new_a.Write(0, buf, buf.Length); //Save data } vm.Write(DEFS.SYSTEM_STATUS_ADDRESS, (long)0); // Write 0 - restore ended for space splen = IO.ReadLong(-1); spcnt = 8; } if (!IMO) { Close(); } TRANSACTIONS_ON = true; }