public DataNode(string path) { this.path = path; //this.tp_element = tp_element; string dbpath = path + "DataNodeStorage.bin"; bool fob_exists = File.Exists(dbpath); FileStream fs = new FileStream(dbpath, FileMode.OpenOrCreate, FileAccess.ReadWrite); fob = new FileOfBlocks(fs); Stream first_stream = fob.GetFirstAsStream(); if (!fob_exists) { PagedStream.InitPagedStreamHead(first_stream, 8L, 0, PagedStream.HEAD_SIZE); fob.Flush(); } main_stream = new PagedStream(fob, fob.GetFirstAsStream(), 8L); //long sz = PagedStream.HEAD_SIZE; // Если main_stream нулевой длины, надо инициировать конфигурацию стримов bool toinit = main_stream.Length == 0; if (toinit) { // инициируем 2 головы для потоков PagedStream.InitPagedStreamHead(main_stream, 0L, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, PagedStream.HEAD_SIZE, 0L, -1L); //PagedStream.InitPagedStreamHead(main_stream, 2 * sz, 0L, -1L); main_stream.Flush(); fob.Flush(); } // создадим 2 потока Stream stream_common_params = new FileStream(path + "common.pac", FileMode.OpenOrCreate, FileAccess.ReadWrite); //new PagedStream(fob, main_stream, 0L); Stream stream_SP_list = new FileStream(path + "splist.pac", FileMode.OpenOrCreate, FileAccess.ReadWrite); //new PagedStream(fob, main_stream, 1 * PagedStream.HEAD_SIZE); //PagedStream stream_offsets = new PagedStream(fob, main_stream, 2 * sz); // пока не знаю для чего... // Создадим ячейки tp_common = new PTypeRecord( new NamedType("configuration", tp_configuration)); cell_common = new PaCell(tp_common, stream_common_params, false); tp_list = new PTypeSequence(KVSequencePortion.tp_pobj); cell_list = new PaCell(tp_list, stream_SP_list, false); // Инициализируем if (toinit) { cell_common.Fill(new object[] { new object[0] }); cell_list.Fill(new object[0]); } common_data = cell_common.Root.Get(); foreach (object[] p in cell_list.Root.ElementValues()) { KVSequencePortion kvsp = new KVSequencePortion(this, p); sportion_list.Add(kvsp); } }
//static string path = "Databases/"; public static void Main4() { Random rnd = new Random(); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); Console.WriteLine("Start demo of table and Universal Index with PagedStorage"); // Тип основной таблицы PType tp_person = new PTypeRecord( new NamedType("id", new PType(PTypeEnumeration.integer)), new NamedType("name", new PType(PTypeEnumeration.sstring)), new NamedType("age", new PType(PTypeEnumeration.real))); // ======================== Теперь нам понадобится страничное хранилище ========================= // файл - носитель хранилища string filepath = dbpath + "storage.bin"; bool fob_exists = File.Exists(filepath); // этот признак используется при разных процессах инициализации // Открываем иили создаем файл-носитель хранилища FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite); // Создаем собственно блочное (страничное) хранилище FileOfBlocks fob = new FileOfBlocks(fs); // Далее идет корявый способ создания трех потоков (Stream), нужных для базы данных Stream first_stream = fob.GetFirstAsStream(); if (!fob_exists) { PagedStream.InitPagedStreamHead(first_stream, 8L, 0, PagedStream.HEAD_SIZE); fob.Flush(); } PagedStream main_stream = new PagedStream(fob, fob.GetFirstAsStream(), 8L); long sz = PagedStream.HEAD_SIZE; // Если main_stream нулевой длины, надо инициировать конфигурацию стримов if (main_stream.Length == 0) { // инициируем 3 головы для потоков PagedStream.InitPagedStreamHead(main_stream, 0L, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, sz, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, 2 * sz, 0L, -1L); main_stream.Flush(); fob.Flush(); } // создадим 3 потока PagedStream stream_person = new PagedStream(fob, main_stream, 0L); PagedStream stream_index = new PagedStream(fob, main_stream, 1 * sz); PagedStream stream_scale = new PagedStream(fob, main_stream, 2 * sz); // =========================== OK ========================== // База данных такая же, как и в программе 3, только вместо файлов используются потоки TableView tab_person = new TableView(stream_person, tp_person); Func <object, int> person_code_keyproducer = v => (int)((object[])((object[])v)[1])[0]; IndexKeyImmutable <int> ind_arr_person = new IndexKeyImmutable <int>(stream_index) { Table = tab_person, KeyProducer = person_code_keyproducer, Scale = null }; ind_arr_person.Scale = new ScaleCell(stream_scale) { IndexCell = ind_arr_person.IndexCell }; IndexDynamic <int, IndexKeyImmutable <int> > index_person = new IndexDynamic <int, IndexKeyImmutable <int> >(true) { Table = tab_person, IndexArray = ind_arr_person, KeyProducer = person_code_keyproducer }; tab_person.RegisterIndex(index_person); fob.DeactivateCache(); int nelements = 1000000; bool toload = true; // Загружать или нет новую базу данных if (toload) { sw.Restart(); // Очистим ячейки последовательности и индекса tab_person.Clear(); IEnumerable <object> flow = Enumerable.Range(0, nelements) .Select(i => { int id = nelements - i; string name = "=" + id.ToString() + "="; double age = rnd.NextDouble() * 100.0; return(new object[] { id, name, age }); }); tab_person.Fill(flow); // Теперь надо отсортировать индексный массив по ключу tab_person.BuildIndexes(); sw.Stop(); Console.WriteLine("Load ok. duration for {0} elements: {1} ms", nelements, sw.ElapsedMilliseconds); } sw.Restart(); // Загрузка кеша ускоряет обработку fob.LoadCache(); sw.Stop(); Console.WriteLine("Cache load duration={0}", sw.ElapsedMilliseconds); // Проверим работу int search_key = nelements * 2 / 3; var ob = index_person.GetAllByKey(search_key) .Select(ent => ((object[])ent.Get())[1]) .FirstOrDefault(); if (ob == null) { throw new Exception("Didn't find person " + search_key); } Console.WriteLine("Person {0} has name {1}", search_key, ((object[])ob)[1]); // Засечем скорость выборок int nte = 10000; sw.Restart(); for (int i = 0; i < nte; i++) { search_key = rnd.Next(nelements) + 1; ob = index_person.GetAllByKey(search_key) .Select(ent => ((object[])ent.Get())[1]) .FirstOrDefault(); if (ob == null) { throw new Exception("Didn't find person " + search_key); } string nam = (string)((object[])ob)[1]; } sw.Stop(); Console.WriteLine("Duration for {2} search in {0} elements: {1} ms", nelements, sw.ElapsedMilliseconds, nte); }
//static string path = "Databases/"; public static void Main5() { Random rnd = new Random(); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); Console.WriteLine("Start demo of table and Universal Index and PagedFileStore"); // Тип основной таблицы PType tp_person = new PTypeRecord( new NamedType("id", new PType(PTypeEnumeration.integer)), new NamedType("name", new PType(PTypeEnumeration.sstring)), new NamedType("age", new PType(PTypeEnumeration.real))); // ======================== Теперь нам понадобится страничное хранилище ========================= // файл - носитель хранилища string filepath = dbpath + "storage3seq.bin"; bool fob_exists = File.Exists(filepath); FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite); FileOfBlocks fob = new FileOfBlocks(fs); Stream first_stream = fob.GetFirstAsStream(); if (!fob_exists) { PagedStream.InitPagedStreamHead(first_stream, 8L, 0, PagedStream.HEAD_SIZE); fob.Flush(); } PagedStream main_stream = new PagedStream(fob, fob.GetFirstAsStream(), 8L); long sz = PagedStream.HEAD_SIZE; // === В main_stream первым объектом поместим тествый поток // Если main_stream нулевой длины, надо инициировать конфигурацию стримов if (main_stream.Length == 0) { // инициируем 3 головы для потоков PagedStream.InitPagedStreamHead(main_stream, 0L, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, sz, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, 2 * sz, 0L, -1L); main_stream.Flush(); fob.Flush(); } // создадим 3 потока PagedStream stream_person = new PagedStream(fob, main_stream, 0L); PagedStream stream_keys = new PagedStream(fob, main_stream, 1 * sz); PagedStream stream_offsets = new PagedStream(fob, main_stream, 2 * sz); // =========================== OK ========================== // Создадим базу данных, состоящую из последовательности, и двух индексных массивов: массива ключей и массива офсетов PaCell person_seq = new PaCell(new PTypeSequence(tp_person), stream_person, false); Func <object, int> person_code_keyproducer = v => (int)((object[])v)[0]; PaCell pers_ind_key_arr = new PaCell(new PTypeSequence(new PType(PTypeEnumeration.integer)), stream_keys, false); PaCell pers_ind_off_arr = new PaCell(new PTypeSequence(new PType(PTypeEnumeration.longinteger)), stream_offsets, false); int nelements = 1000000; bool toload = true; // Загружать или нет новую базу данных if (toload) { sw.Restart(); // При загрузке кеш будет мешаться, его полезно деактивировать fob.DeactivateCache(); // Очистим ячейку последовательности person_seq.Clear(); person_seq.Fill(new object[0]); // Для загрузки нам понадобятся: поток данных, массив ключей и массив офсетов (это всего лишь демонстрация!) IEnumerable <object> flow = Enumerable.Range(0, nelements) .Select(i => { int id = nelements - i; string name = "=" + id.ToString() + "="; double age = rnd.NextDouble() * 100.0; return(new object[] { id, name, age }); }); int[] key_arr = new int[nelements]; long[] off_arr = new long[nelements]; int ind = 0; foreach (object[] orec in flow) { long off = person_seq.Root.AppendElement(orec); int key = (int)(((object[])orec)[0]); key_arr[ind] = key; off_arr[ind] = off; ind++; } person_seq.Flush(); Console.WriteLine("Sequence OK."); // Параллельная сортировка по значению ключа Array.Sort(key_arr, off_arr); pers_ind_key_arr.Clear(); pers_ind_key_arr.Fill(new object[0]); for (int i = 0; i < nelements; i++) { pers_ind_key_arr.Root.AppendElement(key_arr[i]); } pers_ind_key_arr.Flush(); pers_ind_off_arr.Clear(); pers_ind_off_arr.Fill(new object[0]); for (int i = 0; i < nelements; i++) { pers_ind_off_arr.Root.AppendElement(off_arr[i]); } pers_ind_off_arr.Flush(); fob.Flush(); sw.Stop(); Console.WriteLine("Load ok. duration for {0} elements: {1} ms", nelements, sw.ElapsedMilliseconds); } sw.Restart(); fob.LoadCache(); sw.Stop(); Console.WriteLine("Cache load duration={0}", sw.ElapsedMilliseconds); sw.Restart(); int nkeys = (int)pers_ind_key_arr.Root.Count(); int[] keys = new int[nkeys]; int ii = 0; foreach (int k in pers_ind_key_arr.Root.ElementValues()) { keys[ii] = k; ii++; } sw.Stop(); Console.WriteLine("Index preload duration={0}", sw.ElapsedMilliseconds); sw.Restart(); PaEntry entry = person_seq.Root.Element(0); int nte = 10000; for (int i = 0; i < nte; i++) { int key = rnd.Next(nkeys); int ifirst = GetFirstIndexOf(0, nelements, keys, key); long offset = (long)pers_ind_off_arr.Root.Element(ifirst).Get(); entry.offset = offset; object[] rec = (object[])entry.Get(); //Console.WriteLine($"{rec[0]} {rec[1]} {rec[2]}"); } sw.Stop(); Console.WriteLine("Duration={0} for {1}", sw.ElapsedMilliseconds, nte); //// Проверим работу //int search_key = nelements * 2 / 3; //var ob = index_person.GetAllByKey(search_key) // .Select(ent => ((object[])ent.Get())[1]) // .FirstOrDefault(); //if (ob == null) throw new Exception("Didn't find person " + search_key); //Console.WriteLine("Person {0} has name {1}", search_key, ((object[])ob)[1]); //// Засечем скорость выборок //sw.Restart(); //for (int i = 0; i < 1000; i++) //{ // search_key = rnd.Next(nelements); // ob = index_person.GetAllByKey(search_key) // .Select(ent => ((object[])ent.Get())[1]) // .FirstOrDefault(); // if (ob == null) throw new Exception("Didn't find person " + search_key); // string nam = (string)((object[])ob)[1]; //} //sw.Stop(); //Console.WriteLine("Duration for 1000 search in {0} elements: {1} ms", nelements, sw.ElapsedMilliseconds); }
//static string path = "Databases/"; public static void Main8_() { Random rnd = new Random(); //new Random(777); System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch(); Console.WriteLine("Start demo key-value storage"); // Тип основной таблицы PType tp_person = new PTypeRecord( new NamedType("id", new PType(PTypeEnumeration.integer)), new NamedType("name", new PType(PTypeEnumeration.sstring)), new NamedType("age", new PType(PTypeEnumeration.real))); PType tp_index = new PTypeSequence(new PTypeRecord( new NamedType("key", new PType(PTypeEnumeration.integer)), new NamedType("offset", new PType(PTypeEnumeration.longinteger)) )); // ======================== Теперь нам понадобится страничное хранилище ========================= // файл - носитель хранилища string filepath = dbpath + "storage8.bin"; bool fob_exists = File.Exists(filepath); FileStream fs = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.ReadWrite); FileOfBlocks fob = new FileOfBlocks(fs); Stream first_stream = fob.GetFirstAsStream(); if (!fob_exists) { PagedStream.InitPagedStreamHead(first_stream, 8L, 0, PagedStream.HEAD_SIZE); fob.Flush(); } PagedStream main_stream = new PagedStream(fob, fob.GetFirstAsStream(), 8L); long sz = PagedStream.HEAD_SIZE; // === В main_stream первым объектом поместим тествый поток // Если main_stream нулевой длины, надо инициировать конфигурацию стримов if (main_stream.Length == 0) { // инициируем 3 головы для потоков PagedStream.InitPagedStreamHead(main_stream, 0L, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, sz, 0L, -1L); PagedStream.InitPagedStreamHead(main_stream, 2 * sz, 0L, -1L); //PagedStream.InitPagedStreamHead(main_stream, 3 * sz, 0L, -1L); main_stream.Flush(); fob.Flush(); } // создадим 3 потока PagedStream stream_person = new PagedStream(fob, main_stream, 0L); PagedStream stream_keys = new PagedStream(fob, main_stream, 1 * sz); PagedStream stream_offsets = new PagedStream(fob, main_stream, 2 * sz); //PagedStream stream_index = new PagedStream(fob, main_stream, 3 * sz); // =========================== OK ========================== // Создадим базу данных, состоящую из последовательности, и двух индексных массивов: массива ключей и массива офсетов PaCell person_seq = new PaCell(new PTypeSequence(tp_person), stream_person, false); Func <object, int> person_code_keyproducer = v => (int)((object[])v)[0]; PaCell pers_ind_key_arr = new PaCell(new PTypeSequence(new PType(PTypeEnumeration.integer)), stream_keys, false); PaCell pers_ind_off_arr = new PaCell(new PTypeSequence(new PType(PTypeEnumeration.longinteger)), stream_offsets, false); int nelements = 10000000; bool toload = false; // Загружать или нет новую базу данных if (toload) { FileStream tmp_file = new FileStream(dbpath + "tmp.pac", FileMode.CreateNew, FileAccess.ReadWrite); PaCell key_index = new PaCell(tp_index, tmp_file, false); sw.Restart(); // При загрузке кеш будет мешаться, его полезно деактивировать fob.DeactivateCache(); // Очистим ячейку последовательности person_seq.Clear(); person_seq.Fill(new object[0]); // Для загрузки нам понадобятся: поток данных, массив ключей и массив офсетов (это всего лишь демонстрация!) IEnumerable <object> flow = Enumerable.Range(0, nelements) .Select(iv => { int id = nelements - iv; string name = "=" + id.ToString() + "="; double age = rnd.NextDouble() * 100.0; return(new object[] { id, name, age }); }); //int[] key_arr = new int[nelements]; //long[] off_arr = new long[nelements]; key_index.Clear(); key_index.Fill(new object[0]); //int ind = 0; foreach (object[] orec in flow) { long off = person_seq.Root.AppendElement(orec); int key = (int)(((object[])orec)[0]); key_index.Root.AppendElement(new object[] { key, off }); } person_seq.Flush(); key_index.Flush(); Console.WriteLine("Sequence OK. duration={0}", sw.ElapsedMilliseconds); // Сортировка по значению ключа key_index.Root.SortByKey <int>(ob => (int)((object[])ob)[0]); //TODO: Надо "сжать" индексный файл, убрав из него дубли по ключам pers_ind_key_arr.Clear(); pers_ind_key_arr.Fill(new object[0]); foreach (object[] ob in key_index.Root.ElementValues()) { pers_ind_key_arr.Root.AppendElement(ob[0]); } pers_ind_key_arr.Flush(); pers_ind_off_arr.Clear(); pers_ind_off_arr.Fill(new object[0]); foreach (object[] ob in key_index.Root.ElementValues()) { pers_ind_off_arr.Root.AppendElement(ob[1]); } pers_ind_off_arr.Flush(); fob.Flush(); sw.Stop(); Console.WriteLine("Load ok. duration for {0} elements: {1} ms", nelements, sw.ElapsedMilliseconds); key_index.Close(); tmp_file.Dispose(); File.Delete(dbpath + "tmp.pac"); } sw.Restart(); fob.ActivateCache(); fob.LoadCache(); sw.Stop(); Console.WriteLine("Cache load duration={0}", sw.ElapsedMilliseconds); sw.Restart(); //int nkeys = (int)pers_ind_key_arr.Root.Count(); int[] keys = pers_ind_key_arr.Root.ElementValues().Cast <int>().ToArray(); //long[] offsets = key_index.Root.ElementValues().Cast<object[]>().Select(ob => (long)ob[1]).ToArray(); sw.Stop(); Console.WriteLine("Index preload duration={0}", sw.ElapsedMilliseconds); Func <int, Diapason> GetDia = GetDiaFunc2(keys); PaEntry entry = person_seq.Root.Element(0); int search_key = nelements * 2 / 3; ComputeEntry(pers_ind_off_arr, keys, GetDia, entry, search_key); object[] re = (object[])entry.Get(); Console.WriteLine($"{re[0]} {re[1]} {re[2]}"); int nte = 100000; rnd = new Random(); sw.Restart(); for (int i = 0; i < nte; i++) { int key = rnd.Next(keys.Length) + 1; Diapason diap = GetDia(key); int ifirst = Get8FirstIndexOf((int)diap.start, (int)diap.numb, keys, key); if (ifirst == -1) { entry = PaEntry.Empty; Console.WriteLine($"index not found for ..."); continue; } entry.offset = (long)pers_ind_off_arr.Root.Element(ifirst).Get(); object[] rec = (object[])entry.Get(); } sw.Stop(); Console.WriteLine("request test duration={0} for {1}", sw.ElapsedMilliseconds, nte); }