/// <summary> /// Save storage to file /// </summary> /// <param name="name"></param> /// <returns></returns> public void Dump(string path, string name, bool encrypt = false) { string d_path = path; if (d_path != "") { if (!System.IO.Directory.Exists(d_path)) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Dump, path is not found: '" + d_path + "'"); } } else { d_path = System.IO.Directory.GetCurrentDirectory(); } string fname = GenerateDumpFileName(d_path); if (File.Exists(fname)) { File.Delete(fname); } VSIO IO = new VSIO(fname, VSIO.FILE_MODE_CREATE, DEFS.ENCRYPT_DUMP); IO.SetEncryption(encrypt); dump(IO, name); IO.Close(); }
/// <summary> /// Close file and set to null (private) /// </summary> private void CloseTAFile() { if (IO != null) { IO.Close(); IO = null; } }
/// <summary> /// Add partition to space: name - space name; size - size(Mb) /// </summary> /// <param name="name"></param> /// <param name="size">Mb</param> /// <returns></returns> public void AddPartition(string name, int size) { if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'AddPartition' (storage is opened or undefined)"); } VSCatalogDescriptor desc = CATALOG.Get(name); if (desc == null) { throw new VSException(DEFS.E0002_SPACE_NOT_FOUND_CODE, "(" + name + ")"); } if (!this.Lock()) { throw new VSException(DEFS.E0001_UNABLE_TO_LOCK_CODE, "(Add partition)"); } long old_size = desc.SpaceSize; //Calculate space size (in pages) long add_pages = (long)(((size < 1) ? 1 : size) * 1048576) / desc.PageSize; desc.space_size_pg += add_pages; if (!IMO) { // Append pages byte[] dataArray = new byte[desc.PageSize]; VSIO IO = new VSIO(GetSpaceFileName(name, desc.Path, (int)desc.Partitions), VSIO.FILE_MODE_CREATE, ""); byte[] resv = new byte[8]; for (long i = 0; i < add_pages; i++) { IO.Write(-1, DEFS.DATA_NOT_ENCRYPTED); // + 0 (4) Encryption indicator IO.Write(-1, (uint)0); // + 4 (4) CRC32 placeholder IO.Write(-1, ref resv); // +8 (8) reserve IO.Write(-1, ref dataArray); } IO.Close(); desc.partitions++; AddNewAllocation(desc.Path, name, old_size, add_pages * desc.PageSize); CATALOG.Save(); } Release(); }
/// <summary> /// Restore storage from byte array /// </summary> public void RestoreFromArray(byte[] array, string name = "*") { if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Restore' - storage is opened or undefined"); } VSIO IO = new VSIO(array, DEFS.ENCRYPT_DUMP); this.restore(IO, name); IO.Close(); }
/// <summary> /// Open for Rollback/rollforward transaction (NOT USED for IMO!) /// </summary> public void Open() { CURRENT_POS = -1; EOF = false; IO = new VSIO(_path, VSIO.FILE_MODE_OPEN, ""); if (IO.GetLength() == 0) { EOF = true; } else { CURRENT_POS = IO.GetLength(); } roll_mode = true; }
/// <summary> /// Save storage to byte arrray /// </summary> /// <param name="name"></param> /// <returns></returns> public byte[] DumpToArray(string name, bool encrypt = false) { long sz = (this.GetStorageSize() / 4); if (sz > int.MaxValue) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "Storage size is too big for in-memory backup)"); } VSIO IO = new VSIO(null, DEFS.ENCRYPT_DUMP); IO.SetEncryption(encrypt); dump(IO, name); return(IO.GetBytes()); }
/// <summary> /// Restore storage from file /// </summary> public void Restore(string filename = "", string name = "*") { if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Restore' - storage is opened or undefined"); } if (!System.IO.File.Exists(filename)) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Restore' - file is not found: '" + filename + "'"); } VSIO IO = new VSIO(filename, VSIO.FILE_MODE_OPEN, DEFS.ENCRYPT_DUMP); this.restore(IO, name); IO.Close(); }
/*************************************************************************************/ /************************* PRIVATE METHODS ******************************************/ /*************************************************************************************/ /// <summary> /// Update FSAT by adding new element (Extend, AddPartition) or in Create /// </summary> /// <param name="name"></param> /// <param name="address"></param> /// <param name="length"></param> /// <returns></returns> private void AddNewAllocation(string space_path, string name, long address, long length) { VSIO IO = new VSIO(GetSpaceFileName(name, space_path), VSIO.FILE_MODE_OPEN, ""); long h_addr = DEFS.SYSTEM_ALLOCATION_ADDRESS; short n = IO.ReadShort(h_addr); //The number of pending updates long e_addr = h_addr + 2 + (n * 16); IO.Write(e_addr, address); IO.Write(e_addr + 8, address + length); n++; IO.Write(h_addr, n); IO.Close(); }
/// <summary> /// Begin transaction /// </summary> public void Begin() { if (!Started) { if (!imo) { CURRENT_POS = 0; CloseTAFile(); IO = new VSIO(_path, VSIO.FILE_MODE_CREATE, ""); if (IO.GetLength() > 0) { CloseTAFile(); throw new VSException(DEFS.E0018_TRANSACTION_ERROR_CODE, "- Begin transaction - previous transaction is not completed or rolled back"); } } started = true; } }
/// <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(); } }
/// <summary> /// Extend space size: name - space name; size - extension(Mb) /// </summary> /// <param name="name"></param> /// <param name="size (Mb)"></param> /// <returns></returns> public void Extend(string name, int size) { if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Extend' (storage is opened or undefined)"); } VSCatalogDescriptor desc = CATALOG.Get(name); if (desc == null) { throw new VSException(DEFS.E0002_SPACE_NOT_FOUND_CODE, "(" + name + ")"); } if (!IMO) { if (desc.Partitions > 1) // Check if more than 1 partition exists. If so - add partition instead of extending { this.AddPartition(name, size); return; } } if (!this.Lock()) { throw new VSException(DEFS.E0001_UNABLE_TO_LOCK_CODE, "(Extend space)"); } long start_pos = desc.SpaceSize; //Address of the 1st byte out of space //Calculate new allocation size in pages long add_pages = (long)(((size < 1) ? 1 : size) * 1048576) / (long)(desc.PageSize); // Increase space size in descriptor desc.space_size_pg += add_pages; if (!IMO) { //Initialize page buffer byte[] dataArray = new byte[desc.PageSize]; //Append pages VSIO IO = new VSIO(GetSpaceFileName(name, desc.Path), VSIO.FILE_MODE_APPEND, ""); byte[] resv = new byte[8]; for (long i = 0; i < add_pages; i++) { IO.Write(-1, DEFS.DATA_NOT_ENCRYPTED); // + 0 (4) Encryption indicator IO.Write(-1, (uint)0); // + 4 (4) CRC32 placeholder IO.Write(-1, ref resv); // +8 (8) reserve IO.Write(-1, ref dataArray); } IO.Close(); AddNewAllocation(desc.Path, name, start_pos, add_pages * desc.PageSize); CATALOG.Save(); } Release(); }
//==========================================================================================================// //=========================================== Manager ======================================================// //==========================================================================================================// /// <summary> /// Create new address space. Return 0 - successful; -1 - error /// dir - directory /// name - space name /// page size - in Kb /// size - size of the space in Mb. Default - 5 /// extension - size for dynamic extension in MB. Default - 5 /// </summary> /// <param name="name"></param> /// <param name="pagesize"></param> /// <param name="size"></param> /// <returns></returns> public void Create(string name, int pagesize = DEFS.DEFAULT_PAGE_SIZE, int size = DEFS.DEFAULT_SPACE_SIZE, int extension = DEFS.DEFAULT_EXT_SIZE, string path = "") { if (state != DEFS.STATE_DEFINED) { throw new VSException(DEFS.E0025_STORAGE_UNABLE_TO_COMPLETE_CODE, "- 'Create' (storage is opened or undefined)"); } VSCatalogDescriptor desc = CATALOG.Get(name); if (desc != null) { throw new VSException(DEFS.E0024_CREATE_SPACE_ERROR_CODE, "- space already exists(" + name + ")"); } string space_path = path.Trim(); string sname = ""; if (IMO) { space_path = ""; } else { if (space_path == "") { space_path = root_path; } if (!System.IO.Directory.Exists(space_path)) { throw new VSException(DEFS.E0004_STORAGE_NOT_FOUND_CODE, "(" + space_path + ")"); } // Check if directory exists if (!System.IO.Directory.Exists(root_path)) { throw new VSException(DEFS.E0004_STORAGE_NOT_FOUND_CODE, "(" + root_path + ")"); } if (!this.Lock()) { throw new VSException(DEFS.E0001_UNABLE_TO_LOCK_CODE, "(Create space)"); } // Check if file exists, if no - create new space. sname = GetSpaceFileName(name, space_path); if (System.IO.File.Exists(sname)) { throw new VSException(DEFS.E0005_FILE_ALREADY_EXISTS_CODE, "(" + sname + ")"); } } // Add descriptor desc = CATALOG.Create(name, (long)size, (long)extension, (long)pagesize, space_path); desc.IMO = IMO; if (!desc.IMO) { //Create file byte[] dataArray = new byte[desc.PageSize]; VSIO IO = new VSIO(sname, VSIO.FILE_MODE_CREATE, ""); byte[] resv = new byte[8]; for (long i = 0; i < desc.space_size_pg; i++) { IO.Write(-1, DEFS.DATA_NOT_ENCRYPTED); // + 0 (4) Encryption indicator IO.Write(-1, (uint)0); // + 4 (4) CRC32 placeholder IO.Write(-1, ref resv); // +8 (8) reserve IO.Write(-1, ref dataArray); } IO.Write(DEFS.SYSTEM_OWNER_ADDRESS + 16, DEFS.SYSTEM_OWNER_UNDEFINED.PadRight((int)DEFS.SYSTEM_OWNER_LENGTH)); IO.Close(); CATALOG.Save(); } Release(); }
/// <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; }