EmptyClass() { PType tp = new PType(PTypeEnumeration.integer); Polar.Cells.PaCell cell = null; Polar.CellIndexes.TableView table; Polar.PagedStreams.FileOfBlocks fob; }
internal long AppendPObj(PType tp, object valu) { //long off = this.freespace; //this.SetOffset(off); //this.Append(tp, valu); //if (tp.HasNoTail) //{ // this.freespace += tp.HeadSize; //} //else //{ // this.freespace = this.fs.Position; //} long off = this.fs.Position; PaCell.SetPO(tp, bw, valu); this.nElements += 1; this.freespace = tp.HasNoTail ? freespace + tp.HeadSize : fs.Position; return(off); }
public PaEntry(PType tp, long offset, PaCell cell) { this.tp = tp; this.offset = offset; this.cell = cell; }
private void MergeUp(long start, long number1, long number2, KeyString keyfunction) { if (number1 == 0 || number2 == 0) { return; } PTypeSequence pts = (PTypeSequence)typ; int size = pts.ElementType.HeadSize; // Заведем файл для верхнего массива string tmp_name = "../../../Databases/temp.bin"; System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000); // Cкопируем нужное число байтов int buff_size = 8192; byte[] buffer = new byte[buff_size]; PxEntry entry1 = this.Element(start); long pointer = entry1.offset; this.fis.SetOffset(pointer); long bytestocopy = number1 * size; while (bytestocopy > 0) { int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size); tmp.Write(buffer, 0, nb); bytestocopy -= nb; } // Вычислим и запомним во временной ячейке ключи массива 1. // сначала тип ячейки и ячейка: PType tp_tmp = new PType(PTypeEnumeration.sstring); string tmp_cell_name = "../../../Databases/tmp.pac"; PaCell tmp_cell = new PaCell(tp_tmp, tmp_cell_name, false); // теперь заполним ее значениями //tmp_cell.StartSerialFlow(); //tmp_cell.S(); //for (long ii=0; ii<number1; ii++) //{ // string key = keyfunction(entry1); // tmp_cell.V(key); // entry1.offset += size; //} //tmp_cell.Se(); //tmp_cell.EndSerialFlow(); tmp_cell.Fill(new object[0]); for (long ii = 0; ii < number1; ii++) { string key = keyfunction(entry1); tmp_cell.Root.AppendElement(key); entry1.offset += size; } tmp_cell.Flush(); // теперь будем сливать массивы tmp.Position = 0L; // в файле tmp long pointer2 = pointer + number1 * size; long tmp_offset = tmp_cell.Root.Element(0).offset; tmp_cell.SetOffset(tmp_offset); PType tp_sstring = new PType(PTypeEnumeration.sstring); string key1 = (string)tmp_cell.ScanObject(tp_sstring); long cnt1 = 1; // число прочитанных элементов первой подпоследовательности PxEntry entry2 = this.Element(start + number1); string key2 = keyfunction(entry2); long cnt2 = 1; // число прочитанных элементов второй подпоследовательности byte[] buff_el = new byte[size * 8192]; int buff_pos = 0; while (cnt1 > number1 || cnt2 > number2) { if (key1.CompareTo(key2) < 0) { // Продвигаем первую подпоследовательность tmp.Read(buff_el, buff_pos, size); buff_pos += size; key1 = (string)tmp_cell.ScanObject(tp_sstring); cnt1++; } else { // Продвигаем вторую последовательность entry2.fis.SetOffset(entry2.offset); entry2.fis.fs.Read(buff_el, buff_pos, size); buff_pos += size; entry2.offset += size; key2 = keyfunction(entry2); cnt2++; } } // Теперь надо переписать остатки }
private void MergeUp <T>(long start, long number1, long number2, Func <PxEntry, T> keyfunction) { if (number1 == 0 || number2 == 0) { return; } PTypeSequence pts = (PTypeSequence)typ; int size = pts.ElementType.HeadSize; string tmp_name = "../../../Databases/temp.bin"; System.IO.FileStream tmp = new System.IO.FileStream(tmp_name, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite, System.IO.FileShare.None, 10000); // Cкопируем нужное число байтов int buff_size = 8192; byte[] buffer = new byte[buff_size]; PxEntry entry1 = this.Element(start); long pointer = entry1.offset; this.fis.SetOffset(pointer); long bytestocopy = number1 * size; while (bytestocopy > 0) { int nb = this.fis.fs.Read(buffer, 0, bytestocopy < buff_size ? (int)bytestocopy : buff_size); tmp.Write(buffer, 0, nb); bytestocopy -= nb; } // Вычислим и запомним во временной ячейке ключи массива 1. // сначала тип ячейки и ячейка: PxEntry entry2 = this.Element(start + number1); // Это понадобится в будущем, а пока используем для определения типа ключа IComparable key2 = (IComparable)keyfunction(entry2); PType tp_key = key2 is string?new PType(PTypeEnumeration.sstring) : (key2 is int?new PType(PTypeEnumeration.integer) : (key2 is long?new PType(PTypeEnumeration.longinteger) : (key2 is byte?new PType(PTypeEnumeration.@byte) : (key2 is double?new PType(PTypeEnumeration.real) : null)))); PType tp_tmp = new PTypeSequence(tp_key); string tmp_cell_name = "../../../Databases/tmp.pac"; //TODO: Надо имя файла генерировать, а то могут быть коллизии PaCell tmp_cell = new PaCell(tp_tmp, tmp_cell_name, false); // теперь заполним ее значениями //tmp_cell.StartSerialFlow(); //tmp_cell.S(); //for (long ii = 0; ii < number1; ii++) //{ // var key = keyfunction(entry1); // tmp_cell.V(key); // entry1.offset += size; //} //tmp_cell.Se(); //tmp_cell.EndSerialFlow(); tmp_cell.Fill(new object[0]); for (long ii = 0; ii < number1; ii++) { var key = keyfunction(entry1); tmp_cell.Root.AppendElement(key); entry1.offset += size; } tmp_cell.Flush(); // теперь будем сливать массивы tmp.Position = 0L; // в файле tmp long pointer2 = pointer + number1 * size; long tmp_offset = tmp_cell.Root.Element(0).offset; tmp_cell.SetOffset(tmp_offset); //PType tp_sstring = new PType(PTypeEnumeration.sstring); IComparable key1 = (IComparable)tmp_cell.ScanObject(tp_key); long cnt1 = 0; // число переписанных элементов первой подпоследовательности //PxEntry entry2 = this.Element(start + number1); //var key2 = keyfunction(entry2); // Уже прочитан long cnt2 = 0; // число переписанных элементов второй подпоследовательности byte[] buff = new byte[size * 8192]; int buff_pos = 0; while (cnt1 == number1 || cnt2 == number2) { if (key1.CompareTo(key2) < 0) { // Продвигаем первую подпоследовательность tmp.Read(buff, buff_pos, size); buff_pos += size; cnt1++; if (cnt1 < number1) { key1 = (IComparable)tmp_cell.ScanObject(tp_key); // Возможен конец } } else { // Продвигаем вторую последовательность entry2.fis.SetOffset(pointer2); pointer2 += size; entry2.fis.fs.Read(buff, buff_pos, size); buff_pos += size; cnt2++; if (cnt2 < number2) { key2 = (IComparable)keyfunction(entry2); // Возможен конец } } // Если буфер заполнился, его надо сбросить if (buff_pos == buff.Length) { this.fis.SetOffset(pointer); this.fis.fs.Write(buff, 0, buff_pos); pointer += buff_pos; buff_pos = 0; } } // Теперь надо переписать остатки if (cnt1 < number1) { this.fis.SetOffset(pointer); // Здесь запись ведется подряд, без перемещений головки чтения/записи bytestocopy = (number1 - cnt1) * size; while (bytestocopy > 0) { int nbytes = buff.Length - buff_pos; if (bytestocopy < nbytes) { nbytes = (int)bytestocopy; } tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes; this.fis.fs.Write(buff, 0, buff_pos); buff_pos = 0; } } else if (cnt2 < number2) { bytestocopy = (number2 - cnt2) * size; while (bytestocopy > 0) { int nbytes = buff.Length - buff_pos; if (bytestocopy < nbytes) { nbytes = (int)bytestocopy; } this.fis.SetOffset(pointer2); //TODO: Здесь вроде я не то беру, надо разобраться (2 строчки ниже!) pointer2 += nbytes; tmp.Read(buff, buff_pos, nbytes); buff_pos += nbytes; this.fis.SetOffset(pointer); this.fis.fs.Write(buff, 0, buff_pos); pointer += buff_pos; buff_pos = 0; } } }
//================== Сортировки ==================== /// <summary> /// Слияние двух участков одной ячейки первого (он в младшей индексной части) и второго, следующего за ним. /// Результирующий массив начинается с начала первого участка. Слияние производится сравнением объектных значений /// элементов посредством функции сравнения ComparePO /// </summary> /// <param name="tel">Тип элемента последовательности</param> /// <param name="off1">offset начала первого участка</param> /// <param name="number1">длина первого участка</param> /// <param name="off2">offset начала второго участка</param> /// <param name="number2">длина второго участка</param> /// <param name="comparePO">Функция сравнения объектных представлений элементов</param> internal void CombineParts(PType tel, long off1, long number1, long off2, long number2, Func <object, object, int> comparePO) { long pointer_out = off1; long pointer_in = off2; int size = tel.HeadSize; // Используем временный файл string tmp_fname = "tmp_merge.pac"; System.IO.FileStream tmp_fs = new System.IO.FileStream(tmp_fname, System.IO.FileMode.Create, System.IO.FileAccess.ReadWrite); System.IO.BinaryReader tmp_br = new System.IO.BinaryReader(tmp_fs); // Перепишем number1 * size байтов от начальной точки во временный файл (Первую часть) this.SetOffset(pointer_out); long bytestocopy = number1 * size; int buffLen = 8192; byte[] buff = new byte[buffLen * size]; while (bytestocopy > 0) { int nb = bytestocopy < buff.Length ? (int)bytestocopy : buff.Length; this.fs.Read(buff, 0, nb); tmp_fs.Write(buff, 0, nb); bytestocopy -= nb; } tmp_fs.Flush(); // теперь будем сливать массивы long cnt1 = 0; // число переписанных элементов первой подпоследовательности long cnt2 = 0; // число переписанных элементов второй подпоследовательности tmp_fs.Position = 0L; // Установка начальной позиции в файле this.SetOffset(pointer_in); // Установка на начало второй части последовательности в ячейке System.IO.Stream fs1 = tmp_fs; // Первый поток System.IO.Stream fs2 = this.fs; // Второй поток // Микробуфера для элементов byte[] m_buf1 = new byte[size]; byte[] m_buf2 = new byte[size]; // Заполнение микробуферов fs1.Read(m_buf1, 0, size); fs2.Read(m_buf2, 0, size); pointer_in += size; // Это чтобы читать P-значения System.IO.BinaryReader m_reader1 = new System.IO.BinaryReader(new System.IO.MemoryStream(m_buf1)); System.IO.BinaryReader m_reader2 = new System.IO.BinaryReader(new System.IO.MemoryStream(m_buf2)); // Текущие объекты object val1 = PaCell.GetPO(tel, m_reader1); object val2 = PaCell.GetPO(tel, m_reader2); // Писать будем в тот же буффер buff, текущее место записи: int ind_buff = 0; // Слияние!!! while (cnt1 < number1 && cnt2 < number2) { if (comparePO(val1, val2) < 0) { // Продвигаем первую подпоследовательность Buffer.BlockCopy(m_buf1, 0, buff, ind_buff, size); cnt1++; if (cnt1 < number1) // Возможен конец { fs1.Read(m_buf1, 0, size); m_reader1.BaseStream.Position = 0; val1 = PaCell.GetPO(tel, m_reader1); } } else { // Продвигаем вторую последовательность Buffer.BlockCopy(m_buf2, 0, buff, ind_buff, size); cnt2++; if (cnt2 < number2) // Возможен конец { this.SetOffset(pointer_in); // Установка на текущее место чтения !!!!!!!!! fs2.Read(m_buf2, 0, size); pointer_in += size; m_reader2.BaseStream.Position = 0; val2 = PaCell.GetPO(tel, m_reader2); } } ind_buff += size; // Если буфер заполнился, его надо сбросить if (ind_buff == buff.Length) { this.SetOffset(pointer_out); int volume = ind_buff; this.fs.Write(buff, 0, volume); pointer_out += volume; ind_buff = 0; } } // Если в буфере остались данные, их надо сбросить if (ind_buff > 0) { this.SetOffset(pointer_out); int volume = ind_buff; this.fs.Write(buff, 0, volume); pointer_out += volume; } // Теперь надо переписать остатки if (cnt1 < number1) { this.SetOffset(pointer_out); // Здесь запись ведется подряд, без перемещений головки чтения/записи // Сначала запишем уже прочитанную запись this.fs.Write(m_buf1, 0, size); // а теперь - остальное bytestocopy = (number1 - cnt1 - 1) * size; while (bytestocopy > 0) { int nbytes = buff.Length; if (bytestocopy < nbytes) { nbytes = (int)bytestocopy; } fs1.Read(buff, 0, nbytes); this.fs.Write(buff, 0, nbytes); bytestocopy -= nbytes; } } else if (cnt2 < number2) { // Поскольку в тот же массив, то надо переписать только прочитанный, а остатки массива уже на своем месте //this.cell.SetOffset(pointer_out); //this.cell.fs.Write(m_buf2, 0, size); } this.fs.Flush(); // Закрываем временный файл tmp_fs.Flush(); tmp_fs.Dispose(); // Убираем временный файл System.IO.File.Delete(tmp_fname); // не убираем, а то он помещается в мусорную корзину, а так - будет переиспользоваться }