/// <summary> /// Serialize all fields to object fields space /// Free excessive chunks if needed /// </summary> private void serialize() { // If no fields if (FCache.Count == 0) { set_alloc(ALLOC_RESET); FIELDS_SIZE = 0; FreeSpace = -1; FCache = null; return; } byte[] b = null; int old_size = (int)(FIELDS_SIZE); // Current used size (number of fields + all fields size) // 1. Calculate new size int new_size = FIRST_FIELD_OFFSET_REL; for (int i = 0; i < FCache.Count; i++) { new_size += FCache[i].FULL_LENGTH; } // 2. Check if space is availabe, extend if required if (new_size > (old_size + FreeSpace)) { sp.Extend(this, (new_size - old_size)); } // 3. Check if only value update is required List <FieldCache> afc = FCache; FCache = new List <FieldCache>(32); int array_size = (new_size > old_size) ? new_size : old_size; byte[] data = new byte[array_size]; int data_pos = FIRST_FIELD_OFFSET_REL; VSLib.CopyBytes(data, VSLib.ConvertIntToByte(new_size), FIELDS_SIZE_POS, FIELDS_SIZE_LEN); // Size VSLib.CopyBytes(data, VSLib.ConvertShortToByte((short)afc.Count), FIELDS_NUMBER_POS, FIELDS_NUMBER_LEN); // Fields number FCache.Clear(); for (int i = 0; i < afc.Count; i++) { FieldCache fc_element = afc[i]; if (!fc_element.DELETED) { fc_element.OFFSET = data_pos; // Type data[data_pos] = fc_element.TYPE; data_pos++; // Name length data[data_pos] = (byte)(fc_element.NAME.Length); data_pos++; // Name b = VSLib.ConvertStringToByte(fc_element.NAME); VSLib.CopyBytes(data, b, data_pos, b.Length); data_pos += b.Length; // Value if (FIELD_COMPRESS[fc_element.TYPE]) // int/long/decimal { data[data_pos] = (byte)(fc_element.LENGTH); data_pos++; } else if ((fc_element.TYPE == FIELD_TYPE_BYTES) | (fc_element.TYPE == FIELD_TYPE_STRING)) { b = compress(VSLib.ConvertLongToByte(fc_element.LENGTH), FIELD_TYPE_LONG); data[data_pos] = (byte)b.Length; data_pos++; if (b.Length > 0) { VSLib.CopyBytes(data, b, data_pos, b.Length); data_pos += b.Length; } } // Write value if (fc_element.VALUE.Length > 0) { VSLib.CopyBytes(data, fc_element.VALUE, data_pos, fc_element.VALUE.Length); data_pos += afc[i].LENGTH; } // Shift offset and add to cache fc_element.OLDLENGTH = afc[i].LENGTH; fc_element.STATE = STATE_LOADED; FCacheTree.Insert(fc_element.NAME, FCache.Count); FCache.Add(fc_element); } } base.Write(base.FIXED, data, data.Length); set_alloc(ALLOC_RENEW); // Fill the rest by zeros if le length < old length if (new_size < old_size) { long full_used_size = base.FIXED + new_size; b = new byte[old_size - new_size]; base.Write(full_used_size, b, b.Length); // Fill be zeros unused space // Multiple chunks, chech if there are exessive if (base.Chunk > 0) { sp.ShrinkObject(this, full_used_size); } } FreeSpace = (int)(this.Size - base.FIXED - new_size); }
/// <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); }