private int iId; // id of index this table #endregion Fields #region Constructors public Node(Row r, BinaryReader din, int id) { iId = id; rData = r; iBalance = din.ReadInt32(); iLeft = din.ReadInt32(); iRight = din.ReadInt32(); iParent = din.ReadInt32(); if (TracingHelper.AssertEnabled) { TracingHelper.Assert(iBalance != -2); } }
public void Insert(Row before) { if (before == null) { Next = this; Last = this; } else { Next = before; Last = before.Last; before.Last = this; Last.Next = this; } }
public void Free() { Last.Next = Next; Next.Last = Last; if (Next == this) { Next = Last = null; } }
internal Row(Table t, BinaryReader din, int pos, Row before) { tTable = t; int index = tTable.IndexCount; Pos = pos; nFirstIndex = new Node(this, din, 0); Node n = nFirstIndex; for (int i = 1; i < index; i++) { n.nNext = new Node(this, din, i); n = n.nNext; } int l = tTable.InternalColumnCount; oData = Column.ReadData(din, l); int iCurrent = din.ReadInt32(); LogHelper.Publish( String.Format("Row read with {0} columns. Row read position from file: {1}. Current position: {2}.", oData.Length, iCurrent, Pos ), LogEntryType.Debug ); TracingHelper.Check(iCurrent == Pos, TracingHelper.INPUTSTREAM_ERROR); Insert(before); LastAccess = CurrentAccess++; }
/// <summary> /// Remove method declaration. /// This method is used to remove Rows from the Cache. It is called /// by the CleanUp method. /// </summary> /// <param name="row">Row to be removed</param> private void Remove(Row row) { if (TracingHelper.AssertEnabled) TracingHelper.Assert(!row.Changed); // make sure _rowLastChecked does not point to r if (row == _rowLastChecked) { _rowLastChecked = _rowLastChecked.Next; if (_rowLastChecked == row) _rowLastChecked = null; } // make sure _rowData[k] does not point here int k = row.Pos & MASK; if (_rowData[k] == row) { Row n = row.Next; _rowFirst = n; if (n == row || (n.Pos & MASK) != k) n = null; _rowData[k] = n; } // make sure _rowFirst does not point here if (row == _rowFirst) { _rowFirst = _rowFirst.Next; if (row == _rowFirst) _rowFirst = null; } row.Free(); _cacheSize--; }
/// <summary> /// GetWorst method declaration. /// This method finds the Row with the smallest (oldest) iLastAccess member. /// Called by the Cleanup method. /// </summary> /// <returns>The selected Row object</returns> private Row GetWorst() { if (_rowLastChecked == null) _rowLastChecked = _rowFirst; Row r = _rowLastChecked; if (r == null) return null; Row candidate = r; int worst = Row.CurrentAccess; // algorithm: check the next rows and take the worst for (int i = 0; i < 6; i++) { int w = r.LastAccess; if (w < worst) { candidate = r; worst = w; } r = r.Next; } _rowLastChecked = r.Next; return candidate; }
/// <summary> /// </summary> private static void Swap(Row[] w, int a, int b) { Row t = w[a]; w[a] = w[b]; w[b] = t; }
/// <summary> /// </summary> private static void Sort(Row[] w, int l, int r) { int i, j, p; while (r - l > 10) { i = (r + l) >> 1; if (w[l].Pos > w[r].Pos) { Swap(w, l, r); } if (w[i].Pos < w[l].Pos) { Swap(w, l, i); } else if (w[i].Pos > w[r].Pos) { Swap(w, i, r); } j = r - 1; Swap(w, i, j); p = w[j].Pos; i = l; while (true) { if (TracingHelper.StopEnabled) TracingHelper.Stop(); while (w[++i].Pos < p); while (w[--j].Pos > p); if (i >= j) break; Swap(w, i, j); } Swap(w, i, r - 1); Sort(w, l, i - 1); l = i + 1; } for (i = l + 1; i <= r; i++) { if (TracingHelper.StopEnabled) TracingHelper.Stop(); Row t = w[i]; for (j = i - 1; j >= l && w[j].Pos > t.Pos; j--) { w[j + 1] = w[j]; } w[j + 1] = t; } }
/// <summary> /// GetRow method declaration. /// This method reads a Row object from the cache. /// </summary> /// <param name="pos">Offset of the requested Row in the cache</param> /// <param name="table">Table this Row belongs to</param> /// <returns>The Row object as read from the cache.</returns> public Row GetRow(int pos, Table table) { int k = pos & MASK; Row r = _rowData[k]; Row start = r; while (r != null) { if (TracingHelper.StopEnabled) TracingHelper.Stop(); int p = r.Pos; if (p == pos) return r; else if ((p & MASK) != k) break; r = r.Next; if (r == start) break; } Row before = _rowData[k]; if (before == null) { before = _rowFirst; } try { LogHelper.Publish( String.Format("Retrieving row at position: {0}.", pos ), LogEntryType.Debug ); _fileStream.Seek(pos, SeekOrigin.Begin); BinaryReader b = new BinaryReader(_fileStream); int size = b.ReadInt32(); byte[] buffer = new byte[size]; buffer = b.ReadBytes(size); LogHelper.Publish( String.Format("Row Size: {0}. Retrieved {1} bytes.", size, buffer.Length ), LogEntryType.Debug ); MemoryStream bin = new MemoryStream(buffer); BinaryReader din = new BinaryReader(bin, System.Text.Encoding.Unicode); r = new Row(table, din, pos, before); r.Size = size; } catch (IOException e) { #if !POCKETPC Console.WriteLine(e.StackTrace); #endif throw TracingHelper.Error(TracingHelper.FILE_IO_ERROR, "reading: " + e); } _cacheSize++; _rowData[k] = r; _rowFirst = r; return r; }
/// <summary> /// Free method declaration. /// This method marks space in the database file as free. /// </summary> /// <remarks> /// If more than MAX_FREE_COUNT free positios then /// they are probably all are too small anyway; so we start a new list. /// TODO: This is wrong when deleting lots of records. /// </remarks> /// /// <param name="row">Row object to be marked free</param> /// <param name="pos">Offset in the file this Row was stored at</param> /// <param name="length">Size of the Row object to free</param> public void Free(Row row, int pos, int length) { _freeCount++; CacheFree n = new CacheFree(); n.Pos = pos; n.Length = length; if (_freeCount > MAX_FREE_COUNT) _freeCount = 0; else n.Next = _cacheRoot; _cacheRoot = n; // it's possible to remove roots to Remove(row); }
/// <summary> /// Add method declaration. /// This method adds a Row to the Cache. It walks the /// list of CacheFree objects to see if there is available space /// to store the new Row, reusing space if it exists, otherwise /// we grow the file. /// </summary> /// <param name="row">Row to be added to Cache</param> public void Add(Row row) { int size = row.Size; CacheFree f = _cacheRoot; CacheFree last = null; int i = _freePos; while (f != null) { if (TracingHelper.TraceEnabled) { TracingHelper.Stop(); } // first that is long enough if (f.Length >= size) { i = f.Pos; size = f.Length - size; if (size < 8) { // remove almost empty blocks if (last == null) { _cacheRoot = f.Next; } else { last.Next = f.Next; } _freeCount--; } else { f.Length = size; f.Pos += row.Size; } break; } last = f; f = f.Next; } row.Pos = i; if (i == _freePos) { _freePos += size; } int k = i & MASK; Row before = _rowData[k]; if (before == null) { before = _rowFirst; } row.Insert(before); _cacheSize++; _rowData[k] = row; _rowFirst = row; }
public Node(Row r, int id) { iId = id; rData = r; }
public void InsertNoCheck(object[] row, Channel c, bool log) { int i; if (iIdentityColumn != -1) { if (row[iIdentityColumn] == null) { if (c != null) { c.LastIdentity = iIdentityId; } row[iIdentityColumn] = iIdentityId++; } else { i = (int) row[iIdentityColumn]; if (iIdentityId <= i) { if (c != null) { c.LastIdentity = i; } iIdentityId = i + 1; } } } if (iTimestampColumn != -1) { if (row[iTimestampColumn] == null) { row[iTimestampColumn] = DateTime.Now; } else { DateTime timestamp = DateTime.Now; DateTime original = (DateTime) row[iTimestampColumn]; // just in case to assure our timestamp is unique if ( timestamp == original ) { row[iTimestampColumn] = timestamp.AddMilliseconds(1); } else { row[iTimestampColumn] = timestamp; } } } for (i = 0; i < iColumnCount; i++) { if (row[i] == null &&!GetColumn(i).IsNullable) { throw TracingHelper.Error(TracingHelper.TRY_TO_INSERT_NULL); } } try { Row r = new Row(this, row); for (i = 0; i < iIndexCount; i++) { Node n = r.GetNode(i); GetIndex(i).Insert(n); } } catch (Exception e) { // rollback insert for (--i; i >= 0; i--) { GetIndex(i).Delete(row, i == 0); } throw e; // and throw error again } if (c != null) { c.AddTransactionInsert(this, row); } if (lLog != null) { lLog.Write(c, GetInsertStatement(row)); } }