Esempio n. 1
0
        public override IEnumerable <KeyValuePair <K, int> > CompareNonIndexedKeyWithKey <K, T>(
            DbColumn key, DbColumn column, TokenType comparer, T value)
        {
            if (column.Indexed || column.Table.Multikey)
            {
                throw new ArgumentException($"Column {column} must be un-indexed, and belong to a One-Key table");
            }

            //get the key column, index
            var keyColumn      = column.Table.Key;
            int keyColumnIndex = column.Index;
            K   keyValue       = default(K);

            var keyCount = 0;

            //read indexer offsets in their order
            using (var keyReader =
                       new io.BinaryReader(
                           io.File.OpenRead($"{key.Table.Database.BinaryPath}\\{key.Hash}.offset")))
            {
                //amount of keys
                keyCount = keyReader.ReadInt32();

                var count        = Table.Count;
                var initialCount = column.Index;

                var buffer   = new byte[sizeof(UInt64)];
                var bytes    = Table.RowMaskLength;
                var mainMask = Table.RowMask;

                int columnIndex = 0;
                int columnSize  = 0;

                int   bytesToSkip = 0;
                ulong bitMask     = 0;
                ulong recordMask  = 0;

                void SKIP(int cnt)
                {
                    while (cnt-- > 0)
                    {
                        if ((recordMask & bitMask) == 0)
                        {
                            if (columnIndex == keyColumnIndex)
                            {
                                //read Key value into: keyValue
                                keyValue = GetColumnValue <K>();
                            }
                            else
                            {
                                //SKIP
                                //not null value, add according to column type
                                if (columnSize == 0)
                                {
                                    throw new ArgumentException("unsupported type size");
                                }
                                else if (columnSize > 0)
                                {
                                    bytesToSkip += columnSize;
                                }
                                else
                                {
                                    //string, read length, and add chars
                                    reader.BaseStream.Position += bytesToSkip;

                                    //read new bytes to skip
                                    bytesToSkip = reader.ReadByte();
                                }
                            }
                        }
                        bitMask  >>= 1;
                        columnSize = ColumnTypeSizes[++columnIndex];
                    }
                    //position reader
                    if (bytesToSkip > 0)
                    {
                        reader.BaseStream.Position += bytesToSkip;
                    }
                }

                C GetColumnValue <C>()
                {
                    //for string, read length byte
                    var size = (columnSize < 0) ? reader.ReadByte() : columnSize;
                    //create buffer
                    var columnBuffer = new byte[size];

                    //read it
                    reader.Read(columnBuffer, 0, size);
                    //convert it to generic value
                    return(columnBuffer.BitConvertTo <C>());
                }

                for (var ndx = 0; ndx < keyCount; ndx++)
                {
                    var offset = keyReader.ReadInt32();
                    //point to record offset
                    reader.BaseStream.Position = offset;

                    //copy main mask
                    bitMask = mainMask;

                    //read record mask
                    reader.Read(buffer, 0, bytes);
                    recordMask = BitConverter.ToUInt64(buffer, 0);

                    //developer only
                    var binary = Convert.ToString((long)recordMask, 2);

                    //
                    columnSize  = ColumnTypeSizes[columnIndex = 0];
                    bytesToSkip = 0;

                    //skip initial columns if any
                    if (initialCount > 0)
                    {
                        SKIP(initialCount);
                    }

                    //read column value to compare
                    var columnValue = GetColumnValue <T>();

                    if (comparer.Compare <T>(columnValue, value))
                    {
                        if (keyColumnIndex > columnIndex)
                        {
                            //key not read yet
                            SKIP(keyColumnIndex - columnIndex - 1);

                            //read Key value into: keyValue
                            keyValue = GetColumnValue <K>();
                        }

                        yield return(new KeyValuePair <K, int>(keyValue, offset));
                    }
                }
            }
        }
Esempio n. 2
0
 public override IEnumerable <KeyValuePair <K, int> > CompareNonIndexedKeyWithKey <K, T>(DbColumn key, DbColumn column, TokenType comparer, T value)
 {
     throw new NotImplementedException();
 }
Esempio n. 3
0
 /// <summary>
 /// Expensive non-indexed column comparison by a constant value
 /// </summary>
 /// <typeparam name="K">type of column key</typeparam>
 /// <typeparam name="T">type of column</typeparam>
 /// <param name="key">table key</param>
 /// <param name="column">column</param>
 /// <param name="comparer">comparison operator</param>
 /// <param name="value">constant value</param>
 /// <returns>key value pair with key and offset</returns>
 public abstract IEnumerable <KeyValuePair <K, int> > CompareNonIndexedKeyWithKey <K, T>(
     DbColumn key, DbColumn column, TokenType comparer, T value)
     where K : IComparable <K>
     where T : IComparable <T>;
Esempio n. 4
0
        /// <summary>
        /// Expensive non-indexed column comparison by a constant value
        /// </summary>
        /// <typeparam name="T">type of column</typeparam>
        /// <param name="key">table key</param>
        /// <param name="column">column to compare</param>
        /// <param name="comparer">comparison operator</param>
        /// <param name="value">constant value</param>
        /// <returns></returns>
        public override IEnumerable <int> CompareNonIndexedKey <T>(
            DbColumn key, DbColumn column, TokenType comparer, T value)
        {
            //THIS CANNOT BE TOGETHER WITH CompareNonIndexedKeyWithKey BECAUSE
            // RETURNING KEY MAKE AN EXTRA LOAD

            var keyCount = 0;

            //read indexer offsets in their order
            using (var keyReader =
                       new io.BinaryReader(
                           io.File.OpenRead($"{key.Table.Database.BinaryPath}\\{key.Hash}.offset")))
            {
                keyCount = keyReader.ReadInt32();

                var count        = Table.Count;
                var initialCount = column.Index;

                var buffer   = new byte[sizeof(UInt64)];
                var bytes    = Table.RowMaskLength;
                var mainMask = Table.RowMask;

                int   columnIndex = 0;
                int   columnSize  = 0;
                int   bytesToSkip = 0;
                ulong bitMask     = 0;
                ulong recordMask  = 0;

                //build column type translator
                var columnTypeSizes = Table.ColumnTypes.Select(t => t.GetSize()).ToArray();

                void SKIP(int cnt)
                {
                    while (cnt-- > 0)
                    {
                        if ((recordMask & bitMask) == 0)
                        {
                            //not null value, add according to column type
                            var size = columnTypeSizes[columnIndex];
                            if (size == 0)
                            {
                                throw new ArgumentException("unsupported type size");
                            }
                            else if (size > 0)
                            {
                                bytesToSkip += size;
                            }
                            else
                            {
                                //string, read length, and add chars
                                reader.BaseStream.Position += bytesToSkip;


                                //read new bytes to skip
                                bytesToSkip = reader.ReadByte();
                            }
                        }
                        bitMask  >>= 1;
                        columnSize = ColumnTypeSizes[++columnIndex];
                    }
                    //position reader
                    if (bytesToSkip > 0)
                    {
                        reader.BaseStream.Position += bytesToSkip;
                    }
                }

                T GetColumnValue <T>()
                {
                    //for string, read length byte
                    var size = (columnSize < 0) ? reader.ReadByte() : columnSize;
                    //create buffer
                    var columnBuffer = new byte[size];

                    //read it
                    reader.Read(columnBuffer, 0, size);
                    //convert it to generic value
                    return(columnBuffer.BitConvertTo <T>());
                }

                for (var ndx = 0; ndx < keyCount; ndx++)
                {
                    var offset = keyReader.ReadInt32();
                    //point to record offset
                    reader.BaseStream.Position = offset;

                    //copy main mask
                    bitMask = mainMask;

                    //read record mask
                    reader.Read(buffer, 0, bytes);
                    recordMask = BitConverter.ToUInt64(buffer, 0);

                    //developer only
                    var binary = Convert.ToString((long)recordMask, 2);

                    columnSize  = ColumnTypeSizes[columnIndex = 0];
                    bytesToSkip = 0;

                    //skip initial columns if any
                    if (initialCount > 0)
                    {
                        SKIP(initialCount);
                    }

                    //read column value to compare
                    var columnValue = GetColumnValue <T>();

                    //compare
                    if (comparer.Compare <T>(columnValue, value))
                    {
                        yield return(offset);
                    }
                }
            }
        }
Esempio n. 5
0
 /// <summary>
 /// Expensive non-indexed column comparison by a constant value
 /// </summary>
 /// <typeparam name="T">type of column</typeparam>
 /// <param name="key">table key</param>
 /// <param name="column">column</param>
 /// <param name="comparer">comparison operator</param>
 /// <param name="value">constant value</param>
 /// <returns></returns>
 public abstract IEnumerable <int> CompareNonIndexedKey <T>(
     DbColumn key, DbColumn column, TokenType comparer, T value)
     where T : IComparable <T>;
Esempio n. 6
0
        /// <summary>
        /// Fast indexed column coomparison by a constant value
        /// </summary>
        /// <typeparam name="T">type of column</typeparam>
        /// <param name="key">table key</param>
        /// <param name="column">comlumn to compare</param>
        /// <param name="comparer">comparison operator</param>
        /// <param name="value">constant value</param>
        /// <returns></returns>
        internal IEnumerable <KeyValuePair <T, List <int> > > CompareIndexedKeyWithKey <T>(
            DbColumn key, DbColumn column, TokenType comparer, T value)
            where T : IComparable <T>
        {
            var nodeTree = column.IndexTree <T>();
            int offset   = -1;

            var collection = Enumerable.Empty <KeyValuePair <T, List <int> > >();

            if (nodeTree.Root == null)
            {
                //go to .bin file directly, it's ONE page of items
                collection = column.IndexItems <T>()
                             .FindByOper(DbGenerator.ItemsPageStart, value, comparer);
            }
            else
            {
                //this's for tree node page structure
                switch (comparer)
                {
                case TokenType.Equal:                         // "="
                    //find page with key
                    var baseNode = nodeTree.FindKey(value) as PageIndexNodeBase <T>;
                    if (baseNode != null)
                    {
                        switch (baseNode.Type)
                        {
                        case MetaIndexType.Node:
                            //it's in a tree node page
                            var nodePage = baseNode as PageIndexNode <T>;
                            if (nodePage != null && nodePage.Values != null)
                            {
                                collection = new KeyValuePair <T, List <int> >[] {
                                    new KeyValuePair <T, List <int> >(value, nodePage.Values)
                                };
                            }
                            break;

                        case MetaIndexType.Items:
                            //it's in a items page
                            offset = ((PageIndexItems <T>)baseNode).Offset;
                            DbKeyValues <T> item = column.IndexItems <T>().Find(offset, value);
                            if (item != null && item.Values != null)
                            {
                                collection = new KeyValuePair <T, List <int> >[] {
                                    new KeyValuePair <T, List <int> >(value, item.Values)
                                };
                            }
                            break;
                        }
                    }
                    break;

                case TokenType.Less:                         // "<"
                    collection = nodeTree.FindLessKey(value, TokenType.Less);
                    break;

                case TokenType.LessOrEqual:                         // "<="
                    collection = nodeTree.FindLessKey(value, TokenType.LessOrEqual);
                    break;

                case TokenType.Greater:                         // ">"
                    collection = nodeTree.FindGreaterKey(value, TokenType.Greater);
                    break;

                case TokenType.GreaterOrEqual:                          //">="
                    collection = nodeTree.FindGreaterKey(value, TokenType.GreaterOrEqual);
                    break;
                    //throw new ArgumentException($"Operator: {Expression.Operator.Name} not implemented yet!");
                }
            }

            foreach (var ofs in collection)
            {
                yield return(ofs);
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Loads a database schema
        /// </summary>
        /// <param name="reader">binary reader</param>
        /// <returns></returns>
        public static DbSchemaConfig Load(io.BinaryReader reader)
        {
            var schema = new DbSchemaConfig()
            {
                Flags       = (DbSchemaConfigType)reader.ReadUInt32(),
                Version     = reader.BinaryRead(),
                Description = reader.BinaryRead(),
                Name        = reader.BinaryRead(),

                PageSize = reader.ReadInt32(),
                _tables  = new Dictionary <string, DbTable>()
                           //Tables = new List<DbTable>()
            };

            //tables
            var pageCount = reader.ReadInt32();

            for (var t = 0; t < pageCount; t++)
            {
                var table = new DbTable()
                {
                    Name          = reader.BinaryRead(),
                    FileName      = reader.BinaryRead(),
                    Generate      = reader.ReadBoolean(),
                    Multikey      = reader.ReadBoolean(),
                    Rows          = reader.ReadInt32(),
                    RowMask       = reader.ReadUInt64(),
                    RowMaskLength = reader.ReadInt32(),
                    Pager         = DbTablePager.Load(reader),
                    Count         = reader.ReadInt32(),
                    _columns      = new Dictionary <string, DbColumn>()
                };
                //read columns
                var columnNameList = new List <string>();

                for (var c = 0; c < table.Count; c++)
                {
                    var col = new DbColumn()
                    {
                        Indexer = reader.BinaryRead(),
                        Unique  = reader.ReadBoolean(),
                        Name    = reader.BinaryRead(),
                        Index   = reader.ReadInt32(),
                        Type    = reader.BinaryRead(),
                        Key     = reader.ReadBoolean(),
                        Indexed = reader.ReadBoolean(),
                        //
                        NodePages = reader.ReadInt32(),
                        ItemPages = reader.ReadInt32()
                    };
                    if (!table.Add(col))
                    {
                        throw new ArgumentException($"duplicated column: {col.Name} on table {table.Name}");
                    }
                    columnNameList.Add(col.Name);
                }

                //check count
                if (table.Count != table.Columns.Count())
                {
                    throw new ArgumentException($"invalid table count on: {table.Name}");
                }
                table._columnNameList = columnNameList.ToArray();

                //get key
                table.Keys = table.Columns.Where(c => c.Key).ToArray();

                var keyCount = table.Keys.Length;
                if (table.Multikey)
                {
                    //must have more than one key
                    table.Key = null;
                    if (keyCount < 2)
                    {
                        throw new ArgumentException($"table: {table} is multi-key and has less than 2 keys");
                    }
                }
                else
                {
                    //must have just one key
                    if (keyCount != 1)
                    {
                        throw new ArgumentException($"table: {table} must have one key");
                    }
                    table.Key = table.Keys[0];
                }
                //schema.Tables.Add(table);
                schema._tables.Add(table.Name, table);
            }
            return(schema);
        }
Esempio n. 8
0
        void SaveBinaryIndex <T>(BTreePageBase <T> rootPage, DbColumn index)
            where T : IComparable <T>
        {
            if (rootPage == null)
            {
                return;
            }
            var pageCount = rootPage.ChildrenCount;

            Console.WriteLine($"   saving ({pageCount}) page(s)");

            //update column tree page count
            index.NodePages = pageCount;
            index.Table.Database.Modified = true;

            string indexfilepath = io.Path.Combine(Database.BinaryPath, $"{index.Indexer}");

            //page with items .bin
            //this where the main info is
            var indexBinFilePath = indexfilepath + ".bin";

            using (var writer = new io.BinaryWriter(io.File.Create(indexBinFilePath)))
            {
                var collectionPage = GetNodeItemPages <T>(rootPage).ToList();

                //update column item page count
                index.ItemPages = collectionPage.Count;

                //MAIN HEADER

                Int32 pageCollectionCount = collectionPage.Count;
                //write amount of pages
                writer.Write(pageCollectionCount);

                //write index key type
                Int32 keyType = (int)index.TypeEnum;
                writer.Write(keyType);

                //pages
                //sizeof: pageCollectionCount, keyType
                var offset = DbGenerator.ItemsPageStart;                   // 8;
                foreach (var page in collectionPage)
                {
                    page.Offset = offset;
                    //save page
                    var buffer = page.ToBuffer();
                    //
                    offset += buffer.Length;
                    //
                    writer.Write(buffer, 0, buffer.Length);
                }
            }

            //tree page indexer .index
            //this is a light in-memory tree structure for fast search
            using (var writer = new io.BinaryWriter(io.File.Create(indexfilepath)))
            {
                Int32 valueInt32 = 0;
                //write Index main Header
                PageIndexTreeHeader header = new PageIndexTreeHeader();
                //
                header.Value0 = 0;
                //page count
                header.PageCount = pageCount;
                //index.Index
                header.ColumnIndex = index.Index;

                //index.Unique
                //index.Key
                valueInt32 =
                    (index.Unique ? Consts.IndexHeaderIsUnique : 0) |
                    (index.Key ? Consts.IndexHeaderIsKey : 0) |
                    (rootPage.IsLeaf ? Consts.IndexHeaderIsLeaf : 0);

                //index.Type
                //valueInt32 = valueInt32 << 8;
                valueInt32  |= (byte)index.TypeEnum;
                header.Flags = valueInt32;

                //write Header
                byte[] buffer = header.ToByteArray();
                writer.Write(buffer, 0, buffer.Length);

                //test
                var bin = Convert.ToString(header.Flags, 2);

                //write page tree
                if (!rootPage.IsLeaf)
                {
                    StoreTreePage <T>(rootPage, writer);
                }
            }
        }
Esempio n. 9
0
        List <KeyValuePair <T, List <int> > > GenerateIndexCollectionKeysMultipleValues <T>(
            DbColumn index,
            Type indexType,
            string sufix
            )
        {
            //Creating the Type for Generic List.
            Type kp = typeof(KeyValuePair <,>);

            Type[] kpArgs = { indexType, typeof(int) };
            //create generic list type
            Type kpType = kp.MakeGenericType(kpArgs);

            var list = new List <KeyValuePair <T, int> >();

            var listAdd = list.GetType().GetMethod("Add");

            string line;
            //read index data in .TXT file
            var textIndexPath = io.Path.Combine(Database.LogPath, $"{index.Indexer}{sufix}.txt");

            using (var reader = new io.StreamReader(io.File.OpenRead(textIndexPath)))
            {
                while ((line = reader.ReadLine()) != null)
                {
                    var columns = line.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
                    //create kp object
                    var objvalue = System.Convert.ChangeType(columns[0], indexType);

                    var kpObj = Activator.CreateInstance(kpType,
                                                         new object[] {
                        System.Convert.ChangeType(columns[0], indexType),
                        Int32.Parse(columns[1])
                    });
                    listAdd.Invoke(list, new object[] { kpObj });
                }
            }

            //return new list ordered by its Key
            list = list.OrderBy(i => i.Key).ToList();
            //save ordered index
            using (var writer =
                       new io.StreamWriter(io.File.Create(textIndexPath)))
            {
                foreach (var pair in list)
                {
                    writer.WriteLine($"{pair.Key.ToString()}|{pair.Value}");
                }
            }
            //group by key, to see if any duplicates
            //  if any save save as: {index.Indexer}.duplicates.txt

            var groupedList = (from pair in list
                               group pair by pair.Key into g
                               let values = g.Select(p => p.Value).ToList()
                                            select new KeyValuePair <T, List <int> >(g.Key, values))
                              .ToList();

            //save grouped index for reference
            var duplicatedIndexPath = io.Path.Combine(Database.LogPath, $"{index.Indexer}{sufix}.duplicates.txt");

            if (groupedList.Any(g => g.Value.Count > 1))
            {
                using (var writer =
                           new io.StreamWriter(io.File.Create(duplicatedIndexPath)))
                {
                    foreach (var pair in groupedList)
                    {
                        var values = String.Join(", ", pair.Value);
                        writer.WriteLine($"{pair.Key.ToString()}|{values}");
                    }
                }
            }
            else
            {
                //ensure if re-compile changed index keep it updated
                if (io.File.Exists(duplicatedIndexPath))
                {
                    io.File.Delete(duplicatedIndexPath);
                }
            }
            //
            return(groupedList);
        }