/// <summary> /// Dynamically extend partition (single-partition space only). /// Return: 0 - successful; -1 - error. /// </summary> /// <returns></returns> public int Extend() { if (DESCRIPTOR.Partitions > 1) { this.error = "Cannot extend multi-partition space"; return(-1); } //Check if extension is defined while creating space else if (DESCRIPTOR.Extension == 0) { this.error = "Dynamic extension is not defined for this space"; return(-1); } // Initialize new segment int nidx = segments_used; segments_used++; segment_table[nidx] = new page_segment_descriptor(); // Set start-end pages segment_table[nidx].start_page = segment_table[nidx - 1].end_page + 1; segment_table[nidx].end_page = segment_table[nidx].start_page + DESCRIPTOR.extension_pg - 1; // Create new page table long stp = segment_table[nidx].start_page; segment_table[nidx].page_table = new page_descriptor[DESCRIPTOR.extension_pg]; for (int i = 0; i < segment_table[nidx].page_table.Length; i++) { if (imo) { segment_table[nidx].page_table[i].page_state = DEFS.PAGE_READ; segment_table[nidx].page_table[i].page_lock = DEFS.PAGE_LOCKED; segment_table[nidx].page_table[i].bufno = (int)(stp + i); // For IMO bufno = page table element } else { segment_table[nidx].page_table[i].page_state = DEFS.PAGE_FREE; segment_table[nidx].page_table[i].page_lock = DEFS.PAGE_UNLOCKED; segment_table[nidx].page_table[i].bufno = -1; } } //Add extension information short n = ReadShort(DEFS.SYSTEM_ALLOCATION_ADDRESS); // The number of pending updates long e_addr = DEFS.SYSTEM_ALLOCATION_ADDRESS + 2 + (n * 16); //Write(e_addr, DESCRIPTOR.Size); Write(e_addr, DESCRIPTOR.SpaceSize); // Start addrress long end_address = DESCRIPTOR.SpaceSize + DESCRIPTOR.Extension; // End address + 1 Write(e_addr + 8, end_address); // Update number of extensions n++; Write(DEFS.SYSTEM_ALLOCATION_ADDRESS, (short)n); // Save old physical size long old_size = DESCRIPTOR.SysSpaceSize; // Increase space size DESCRIPTOR.space_size_pg += DESCRIPTOR.extension_pg; if (imo) // In Memory Option extension { // Create new cache (IMO) segment_table[nidx].cache = new page_buffer[DESCRIPTOR.extension_pg]; for (int i = 0; i < segment_table[nidx].cache.Length; i++) { segment_table[nidx].cache[i].buf = new byte[page_size]; segment_table[nidx].cache[i].tbuf = null; segment_table[nidx].cache[i].last_access = 0; segment_table[nidx].cache[i].access_count = 0; segment_table[nidx].cache[i].page_no = i; // Page no = Buf no segment_table[nidx].cache[i].prev = -1; segment_table[nidx].cache[i].next = -1; } } else { // Append pages to the physical storage byte[] resv = new byte[8]; byte[] dataArray = new byte[page_size]; try { for (int i = 0; i < DESCRIPTOR.extension_pg; i++) { long addr = old_size + (i * (DESCRIPTOR.PageSize + DEFS.SYSTEM_USED_PAGE_SPACE)); pd[0].fs.Write(addr, DEFS.DATA_NOT_ENCRYPTED); // + 0 (4) Encryption indicator pd[0].fs.Write(-1, (uint)0); // + 4 (4) CRC32 placeholder pd[0].fs.Write(-1, ref resv); // +8 (8) reserve pd[0].fs.Write(-1, ref dataArray); } } catch (Exception e) { this.error = "Error while extending file: " + e.Message; return(-1); } // Increase file descriptor pages pd[0].end_page += DESCRIPTOR.extension_pg; DESCRIPTOR.CATALOG.Save(); if (DESCRIPTOR.SysSpaceSize != pd[0].fs.GetLength()) { throw new Exception("Descriptor and file size doesnt match: " + DESCRIPTOR.SysSpaceSize.ToString() + " - " + pd[0].fs.GetLength().ToString()); } } return(0); }
/// <summary> /// Open new address space: _path - root folder path; _cat_file - catalog file name; idx - index in the catalog. Return: space id or -1(if error) /// </summary> /// <param name="_path"></param> /// <param name="_cat_file"></param> /// <param name="idx"></param> /// <returns></returns> public string Open(VSCatalogDescriptor desc, VSTransaction ta) { this.DESCRIPTOR = desc; this.page_size = DESCRIPTOR.PageSize; this.imo = DESCRIPTOR.IMO; e_key = VSLib.ConvertStringToByte(DEFS.ENCRYPT_SPACE); e_buf = new byte[page_size]; _ta = ta; ////////////////////////////////////////////// ///////////// Initiate partitions //////////// ////////////////////////////////////////////// this.pd = new partition_descriptor[DESCRIPTOR.Partitions]; //Check if all partitions exists if (imo) { pd[0].start_page = 0; //Start Page pd[0].end_page = DESCRIPTOR.space_size_pg - 1; //End Page } else { for (int i = 0; i < DESCRIPTOR.Partitions; i++) { short j = (short)(i + 1); pd[i].file_name = DESCRIPTOR.Path + "\\" + DEFS.SPACE_FILE_NAME(DESCRIPTOR.Name, i); if (!System.IO.File.Exists(pd[i].file_name)) { return("Error: space file is not found - " + pd[i].file_name); } //FileStream f = null; //f = File.Open(pd[i].file_name, FileMode.Open, FileAccess.ReadWrite, FileShare.None); pd[i].fs = new VSIO(pd[i].file_name, VSIO.FILE_MODE_OPEN, DEFS.ENCRYPT_SPACE); pd[i].fs.SetEncryption(false); pd[i].start_page = (i == 0) ? 0 : pd[i - 1].end_page + 1; //Start Page pd[i].end_page = pd[i].start_page + ((pd[i].fs.GetLength()) / page_size) - 1; //End Page } } ////////////////////////////////////////////// ///////////// Initiate cache ///////////////// ////////////////////////////////////////////// // Create segment table segment_table = new page_segment_descriptor[DEFS.PAGE_SEGMENTS_NUMBER]; // Create page table for 1st segment segment_table[0] = new page_segment_descriptor(); segment_table[0].start_page = 0; segment_table[0].end_page = DESCRIPTOR.space_size_pg - 1; // Set initial number of segments used segments_used = 1; // Calculate cache size in pages if (imo) { cache_size_pages = DESCRIPTOR.space_size_pg; cache_size_bytes = DESCRIPTOR.SpaceSize; } else { string confs = VSLib.VSGetKey(DEFS.VM_CACHE_SIZE_KEY); if (confs == "") { confs = DEFS.VM_CACHE_SIZE_DEFAULT; VSLib.VSSetKey(DEFS.VM_CACHE_SIZE_KEY, confs); } int csize = VSLib.ConvertStringToInt(confs); cache_size_bytes = ((csize < 2) ? 2 : csize) * 1048576; if (cache_size_bytes < (page_size * 10)) { cache_size_bytes = page_size * 10; } cache_size_pages = (cache_size_bytes / page_size) + 1; } // Initialize cache segment_table[0].cache = new page_buffer[cache_size_pages]; for (int i = 0; i < cache_size_pages; i++) { segment_table[0].cache[i].buf = new byte[page_size]; segment_table[0].cache[i].tbuf = null; segment_table[0].cache[i].last_access = 0; segment_table[0].cache[i].access_count = 0; if (imo) { segment_table[0].cache[i].page_no = i; // Page no = Buf no segment_table[0].cache[i].prev = -1; segment_table[0].cache[i].next = -1; } else { segment_table[0].cache[i].page_no = -1; segment_table[0].cache[i].prev = i - 1; segment_table[0].cache[i].next = ((i + 1) == cache_size_pages) ? -1 : i + 1; } } // Initialize queues (not IMO) if (!imo) { q_read = new int[3]; q_read[number] = 0; q_read[first] = -1; q_read[last] = -1; q_write = new int[3]; q_write[number] = 0; q_write[first] = -1; q_write[last] = -1; q_free = new int[3]; q_free[number] = (int)cache_size_pages; q_free[first] = 0; q_free[last] = (int)cache_size_pages - 1; } ////////////////////////////////////////////// ///////////// Initiate page table //////////// ////////////////////////////////////////////// segment_table[0].page_table = new page_descriptor[DESCRIPTOR.space_size_pg]; for (int i = 0; i < segment_table[0].page_table.Length; i++) { if (imo) { segment_table[0].page_table[i].page_state = DEFS.PAGE_READ; segment_table[0].page_table[i].page_lock = DEFS.PAGE_LOCKED; segment_table[0].page_table[i].bufno = i; // For IMO bufno = page table element } else { segment_table[0].page_table[i].page_state = DEFS.PAGE_FREE; segment_table[0].page_table[i].page_lock = DEFS.PAGE_UNLOCKED; segment_table[0].page_table[i].bufno = -1; } } // Set state 'Opened' this.state = DEFS.SPACE_OPENED; // For IMO: write owner 'undefined'; otherwise: load and lock page 0. if (imo) { this.Write(DEFS.SYSTEM_OWNER_ADDRESS, DEFS.SYSTEM_OWNER_UNDEFINED.PadRight((int)DEFS.SYSTEM_OWNER_LENGTH)); } else { fetch(0, 0, 0, DEFS.PAGE_READ); this.lock_page(0); // lock 1st page } return(""); }