public int ChainCompare(int[] cmp, NdxFile index, NdxEntry other) { this.Fields.ChainCompare(other.Fields, cmp); // to do check for ascending descending for (int i = 0; i < cmp.Length; i++) { if (cmp[i] != 0) return cmp[i]; } // if we're here the fields are identical // we compare RecordNo when the index is NOT unique if (index.mNdxHeader.UniqueFlag) return 0; else return DbfRecordNo.CompareTo(other.DbfRecordNo); }
internal void Dump(string indent, NdxPage parentPage, NdxEntry parentEntry, bool withChildren, ref NdxEntry lastLeaf) { var ndxFile = (NdxFile)mHolder.mFile; System.Diagnostics.Debug.WriteLine(indent + "Page #" + mHolder.RecordNo +" " + this.EntriesCount + " entries (parent: " + (ParentPage == null ? "none" : "#" + ParentPage.RecordNo)+")"); System.Diagnostics.Debug.Assert(parentPage == ParentPage, "Invalid NDX Parent page"); for (int i = 0; i < EntriesCount; i++) { var e = GetEntry(i); System.Diagnostics.Debug.WriteLine( indent + " " + "Entry " + i + " (page #" + mHolder.RecordNo + ") - " + " SubPage: " + (e.LowerPageRecordNo == UInt32.MaxValue ? "none" : "#" + e.LowerPageRecordNo) + ", Key: " + e.Fields.ToString() + " #" + e.DbfRecordNo ); if (e.mNdxNativeLowerPageNo != 0) { NdxPage subPage = (NdxPage)ndxFile.InternalGetPage(this, (uint)e.LowerPageRecordNo, /*returnNullIfNotInCache*/ false); if (withChildren) { subPage.Dump(indent + " ", this, e, true, ref lastLeaf); } } else { #if DEBUG if (lastLeaf != null) { int[] cmpArray = new int[ndxFile.mSortFieldsCount]; int cmp = e.ChainCompare(cmpArray, ndxFile, lastLeaf); if (cmp <= 0) System.Diagnostics.Trace.WriteLine("*** ERRROR HERE THE ORDER IS MESSED UP ***"); } lastLeaf = e; #endif } } }
private void SplitPage() { #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("Split page #" + this.RecordNo); #endif var ndxFile = (NdxFile)mHolder.mFile; // split needed (on save) int mid = EntriesCount / 2; if (ParentPage == null) { ParentPage = (NdxPage)ndxFile.NewPage(null); var rootEntry = new NdxEntry(); var lastEntry = GetEntry(EntriesCount - 1); rootEntry.DbfRecordNo = lastEntry.DbfRecordNo; rootEntry.Fields = lastEntry.Fields.Clone(); rootEntry.LowerPageRecordNo = this.RecordNo; ParentPage.EntriesClear(); ParentPage.EntriesInsert(0,rootEntry); ndxFile.mNdxHeader.StartingPageRecordNo = ParentPage.RecordNo; //ParentPage.mNbChildEntries = mNbChildEntries; ParentPage.mIsModified = true; #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine(" Create new parent page #" + mParentPage.RecordNo); mParentPage.Dump(" "); #endif } var newPage = (NdxPage)ndxFile.NewPage(ParentPage); newPage.EntriesClear(); newPage.mIsModified = true; newPage.ParentPage = ParentPage; for (int i = 0; i < mid; i++) { //mNbChildEntries = mNbChildEntries; newPage.EntriesInsert(i, GetEntry(i)); var lowerPageRecordNo = GetEntry(i).LowerPageRecordNo; if (lowerPageRecordNo != UInt32.MaxValue) { var ndxPage2 = ndxFile.InternalGetPage( ParentPage, lowerPageRecordNo, /* returnNullIfNotInCache */ true) as NdxPage; if (ndxPage2 != null) { ndxPage2.ParentPage = newPage; } } } EntriesRemoveRange(0, mid); var midEntry = newPage.GetEntry(mid - 1); var newMidEntry = new NdxEntry() { DbfRecordNo = midEntry.DbfRecordNo, LowerPageRecordNo = newPage.RecordNo, Fields = midEntry.Fields.Clone() }; #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine(" newPage #" + newPage.RecordNo); newPage.Dump(" "); System.Diagnostics.Trace.WriteLine(" this page #" + RecordNo); Dump(" "); #endif int midEntryPos = ParentPage.FindInsertPos(newMidEntry, ndxFile); ParentPage.InsertInThisPage(newMidEntry, midEntryPos); }
private void SetEntry(int pos, NdxEntry newEntry) { #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("Setting entry #" + pos + ":" + newEntry.Fields.ToString() + " #" + newEntry.DbfRecordNo + " in page #" + this.RecordNo); #endif mEntries[pos] = newEntry; }
private void PropagateLastEntryChanged(NdxEntry newEntry) { var ndxFile = (NdxFile)mHolder.mFile; var page = this; var parentPage = ParentPage; int pos; while (parentPage != null) { bool equal; parentPage.FindPos(newEntry, ndxFile, out equal, out pos); if (pos == parentPage.mEntries.Count) pos--; var originalParentEntry = parentPage.GetEntry(pos); if (page.RecordNo != originalParentEntry.LowerPageRecordNo) { ndxFile.Dump(); System.Diagnostics.Debug.Assert( page.RecordNo == originalParentEntry.LowerPageRecordNo, "invalid LowerPageRecordNo"); } NdxEntry newParentEntry = new NdxEntry() { DbfRecordNo = newEntry.DbfRecordNo, LowerPageRecordNo = page.RecordNo, Fields = newEntry.Fields.Clone() }; #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("Propagate LastEntry in page #" + parentPage.RecordNo + " entry " + pos); System.Diagnostics.Trace.WriteLine("before propagate"); parentPage.Dump(" "); #endif parentPage.SetEntry(pos, newParentEntry); #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("after propagate"); parentPage.Dump(" "); #endif if (pos < parentPage.EntriesCount - 1) break; page = parentPage; parentPage = page.ParentPage; } }
private void InsertInThisPage(NdxEntry newEntry, int pos) { #if DUMP_INSERTS working++; System.Diagnostics.Trace.WriteLine("Inserting entry " + newEntry.Fields.ToString() + " #" + newEntry.DbfRecordNo + " in page #" + this.RecordNo); #endif System.Diagnostics.Debug.Assert(this.RecordNo != UInt32.MaxValue, "RecordNo should be set."); var ndxFile = (NdxFile)mHolder.mFile; // find the EntriesInsert(pos, newEntry); if (pos == EntriesCount - 1) // we inserted in the last entry { PropagateLastEntryChanged(newEntry); } if (EntriesCount > ndxFile.mNdxHeader.NoOfKeysPerPage) SplitPage(); mIsModified = true; }
private void FindPos(NdxEntry newEntry, NdxFile ndxFile, out bool equal, out int pos) { int min = 0; int max = EntriesCount - 1; int[] cmpArray = new int[ndxFile.mSortFieldsCount]; #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("Searching entry '" + newEntry.Fields.ToString() + " #" + newEntry.DbfRecordNo + "' position in page #" + this.RecordNo); Dump(" "); #endif while (max >= min) { int mid = (min + max) / 2; NdxEntry other = GetEntry(mid); int cmp = newEntry.ChainCompare(cmpArray, ndxFile, other); if (cmp > 0) min = mid + 1; else if (cmp < 0) max = mid - 1; else { equal = true; pos = mid; return; } } #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine(" Result:" + min); #endif equal = false; pos = min; }
private int FindInsertPos(NdxEntry newEntry, NdxFile ndxFile) { int pos; bool equal; FindPos(newEntry, ndxFile, out equal, out pos); if (equal) throw new Exception("Duplicated entries in the Index file."); return pos; }
private void EntriesInsert(int pos, NdxEntry newEntry) { #if DEBUG var ndxFile = (NdxFile)mHolder.mFile; int[] cmpArray = new int[ndxFile.mSortFieldsCount]; int cmp; if (pos > 0) { NdxEntry previousEntry = GetEntry(pos - 1); cmp = newEntry.ChainCompare(cmpArray, ndxFile, previousEntry); if (cmp < 0) { Dump("NdxPage.EntriesInsert:", ""); System.Diagnostics.Debug.Assert(false, "Node should be bigger than previous node."); } } if (pos < mEntries.Count) { NdxEntry nextEntry = GetEntry(pos); cmp = newEntry.ChainCompare(cmpArray, ndxFile, nextEntry); if (cmp > 0) { Dump("NdxPage.EntriesInsert:", ""); System.Diagnostics.Debug.Assert(false, "Node should be less than previous node."); } } #endif mEntries.Insert(pos, newEntry); #if DUMP_INSERTS System.Diagnostics.Trace.WriteLine("Entries.Insert @" + pos + ":" + newEntry.Fields.ToString() + " #" + newEntry.DbfRecordNo + " in page #" + this.RecordNo); Dump(" "); #endif }
private void DeleteInThisPage(NdxEntry newEntry, int pos) { #if DUMP_INSERTS working++; System.Diagnostics.Trace.WriteLine("Inserting entry " + newEntry.Fields.ToString() + " #" + newEntry.DbfRecordNo + " in page #" + this.RecordNo); #endif System.Diagnostics.Debug.Assert(this.RecordNo != UInt32.MaxValue, "RecordNo should be set."); var ndxFile = (NdxFile)mHolder.mFile; // find the EntriesRemove(pos); if (EntriesCount == 0) { Utils.Nop(); } else if (pos == EntriesCount) // we delete the last entry { var lastEntry = GetEntry(pos - 1); PropagateLastEntryChanged(lastEntry); } mIsModified = true; }
internal void OnReadRecord(byte[] buffer) { var ndxFile = (NdxFile)mHolder.mFile; #if DUMP_READ_RECORD System.Diagnostics.Trace.WriteLine("NdxPage.OnReadRecord Page#" + this.RecordNo); System.Diagnostics.Trace.WriteLine(Utils.HexDump(buffer)); #endif EntriesClear(); int nbEntries = BitConverter.ToInt32(buffer, 0); int pos = 4; Byte[] fieldsBuffer = ndxFile.mSortFieldsReadBuffer; for (int i = 0; i < nbEntries; i++) { var ndxEntry = new NdxEntry(); ndxEntry.mNdxNativeLowerPageNo = BitConverter.ToUInt32(buffer, pos); pos += 4; ndxEntry.DbfRecordNo = BitConverter.ToUInt32(buffer, pos); pos += 4; object fields = ndxFile.mSortFieldsConstructor.Invoke(null); Array.Copy(buffer, pos, fieldsBuffer, 0, fieldsBuffer.Length); ndxFile.mSortFieldsWriter.mQuickReadMethod(ndxFile, fieldsBuffer, fields); pos += fieldsBuffer.Length; ndxEntry.Fields = (SortFields)fields; #if DUMP_READ_RECORD System.Diagnostics.Trace.WriteLine(" Entry " + i + " (Page #" + this.RecordNo + ") " + fields.ToString() + " " + ndxEntry.Fields.ToString() + " " + ndxEntry.DbfRecordNo); #endif EntriesInsert(i, ndxEntry); } }
internal void LocateAndInsert(NdxEntry newEntry) { var ndxFile = (NdxFile)mHolder.mFile; int originalPos = FindInsertPos(newEntry, ndxFile); int pos = originalPos; if (pos == EntriesCount) pos--; bool hasLowerPage = (pos >= 0 && GetEntry(pos).LowerPageRecordNo != UInt32.MaxValue); if (hasLowerPage) { var ndxPage2 = ndxFile.InternalGetPage(this, GetEntry(pos).LowerPageRecordNo, /* returnNullIfNotInCache */ false) as NdxPage; ndxPage2.LocateAndInsert(newEntry); } else { InsertInThisPage(newEntry, originalPos); } }
internal void LocateAndDelete(NdxEntry entry) { var ndxFile = (NdxFile)mHolder.mFile; bool equal; int originalPos; FindPos(entry, ndxFile, out equal, out originalPos); if (originalPos == EntriesCount) originalPos--; bool hasLowerPage = (originalPos >= 0 && GetEntry(originalPos).LowerPageRecordNo != UInt32.MaxValue); if (hasLowerPage) { var ndxPage2 = ndxFile.InternalGetPage(this, GetEntry(originalPos).LowerPageRecordNo, /* returnNullIfNotInCache */ false) as NdxPage; ndxPage2.LocateAndDelete(entry); } else { System.Diagnostics.Debug.Assert(equal == true, "Can't find and remove NDX entry."); DeleteInThisPage(entry, originalPos); } }