public int Count() { lock (this.store._Locker) { int skipped = 0; int taken = 0; ExecutionPlan executionplan = FilterParser <TKey, TValue> .GetExecutionPlan(this); List <List <long> > rangelist = new List <List <long> >(); List <TValue> returnlist = new List <TValue>(); foreach (var item in executionplan.indexRanges) { /// check if the primary key is included. List <long> blockpositionList = new List <long>(); ItemCollection collection = this.store.Indexes.getIndex(item.Key).GetCollection(item.Value.lower, item.Value.upper, item.Value.lowerOpen, item.Value.upperOpen, this.Ascending); foreach (Int64 position in collection) { blockpositionList.Add(position); } rangelist.Add(blockpositionList); } bool itemMatch = true; foreach (Int64 item in executionplan.startCollection) { /// check matches. itemMatch = true; foreach (List <long> rangeitem in rangelist) { if (!rangeitem.Contains(item)) { itemMatch = false; break; } } if (!itemMatch) { continue; } /// check column matchs. foreach (ColumnScan plan in executionplan.scanColumns) { byte[] columnbytes = this.store.getColumnsBytes(item, plan.relativeStartPosition, plan.length); if (!plan.Evaluator.isMatch(columnbytes)) { itemMatch = false; break; } } if (!itemMatch) { continue; } /// pass all tests. if (skipped < this.SkipCount) { skipped += 1; continue; } taken += 1; } executionplan = null; return(taken); } }
/// <summary> /// prase the filter collection and get an execution plan. /// </summary> /// <returns></returns> public static ExecutionPlan GetExecutionPlan(Filter <TKey, TValue> filter) { ExecutionPlan executionplan = new ExecutionPlan(); //first check order by field. if (filter.OrderByPrimaryKey) { // does not support range with primary key yet, will be supported later. Range <byte[]> primaryrange = getRange(filter.store.StoreSetting.PrimaryKey, filter.items); if (primaryrange != null) { executionplan.startCollection = filter.store.primaryIndex.getCollection(primaryrange.lower, primaryrange.upper, primaryrange.lowerOpen, primaryrange.upperOpen, filter.Ascending); } else { executionplan.startCollection = filter.store.primaryIndex.allItemCollection(filter.Ascending); } // executionplan.OrderBySettled = true; executionplan.hasStartCollection = true; } else { if (!string.IsNullOrEmpty(filter.OrderByFieldName)) { if (filter.store.Indexes.HasIndex(filter.OrderByFieldName)) { Range <byte[]> range = getRange(filter.OrderByFieldName, filter.items); if (range != null) { executionplan.startCollection = filter.store.Indexes.getIndex(filter.OrderByFieldName).GetCollection(range.lower, range.upper, range.lowerOpen, range.upperOpen, filter.Ascending); } else { executionplan.startCollection = filter.store.Indexes.getIndex(filter.OrderByFieldName).AllItems(filter.Ascending); } // executionplan.OrderBySettled = true; executionplan.hasStartCollection = true; } } } // check the primary key index. Range <byte[]> primarykeyrange = getRange(filter.store.StoreSetting.PrimaryKey, filter.items); if (primarykeyrange != null) { executionplan.startCollection = filter.store.primaryIndex.getCollection(primarykeyrange.lower, primarykeyrange.upper, primarykeyrange.lowerOpen, primarykeyrange.upperOpen, filter.Ascending); executionplan.hasStartCollection = true; } // check all index fields that has been used in the filter. foreach (var item in filter.store.Indexes.items) { Range <byte[]> indexrange = getRange(item.FieldName, filter.items); if (indexrange != null) { executionplan.indexRanges.Add(item.FieldName, indexrange); } } // now parse columns. All query where condition item must be in columns, otherwise this will be a problem. foreach (var item in filter.items) { Columns.IColumn <TValue> column; column = filter.store.GetColumn(item.FieldOrProperty); if (column != null) { ColumnScan colplan = new ColumnScan(); colplan.ColumnName = column.FieldName; colplan.relativeStartPosition = column.relativePosition; colplan.length = column.Length; colplan.Evaluator = ColumnEvaluator.GetEvaluator(column.DataType, item.Compare, item.Value, column.Length); executionplan.scanColumns.Add(colplan); } else { throw new Exception("filter field must be index or column, add them to colomn or index when creating the store, otherwise use the fullscan option"); } } foreach (var item in filter.InItems) { Columns.IColumn <TValue> column; column = filter.store.GetColumn(item.Key); if (column != null) { ColumnScan colplan = new ColumnScan(); colplan.ColumnName = column.FieldName; colplan.relativeStartPosition = column.relativePosition; colplan.length = column.Length; colplan.Evaluator = ColumnInEvaluator.GetInEvaluator(column.DataType, item.Value, column.Length); executionplan.scanColumns.Add(colplan); } else { throw new Exception("filter field must be index or column, add them to colomn or index when creating the store, otherwise use the fullscan option"); } } /// for the methods calls. foreach (var item in filter.calls) { MemberExpression memberaccess = null; foreach (var xitem in item.Arguments) { if (xitem.NodeType == ExpressionType.MemberAccess) { memberaccess = xitem as MemberExpression; } } if (memberaccess == null) { throw new Exception("Method call require use one of the Fields or Property as parameters"); } string fieldname = memberaccess.Member.Name; Columns.IColumn <TValue> column; column = filter.store.GetColumn(fieldname); if (column != null) { ColumnScan colplan = new ColumnScan(); colplan.ColumnName = column.FieldName; colplan.relativeStartPosition = column.relativePosition; colplan.length = column.Length; colplan.Evaluator = ColumnMethodCallEvaluator.GetMethodEvaluator(column.DataType, column.Length, item); executionplan.scanColumns.Add(colplan); } else { throw new Exception("methed call parameter must be a column, add the field to colomn creating creating the store, otherwise use the fullscan option"); } } /// verify the plan. or optimize it. if (!executionplan.hasStartCollection) { //make one of the range. pick any one now. should be pick by the optimizer. foreach (var item in executionplan.indexRanges) { IIndex <TValue> index = filter.store.Indexes.getIndex(item.Key); if (index != null) { executionplan.startCollection = index.GetCollection(item.Value.lower, item.Value.upper, item.Value.lowerOpen, item.Value.upperOpen, filter.Ascending); executionplan.hasStartCollection = true; executionplan.indexRanges.Remove(item.Key); break; } } if (!executionplan.hasStartCollection) { executionplan.startCollection = filter.store.primaryIndex.allItemCollection(filter.Ascending); executionplan.hasStartCollection = true; } } return(executionplan); }