private int iId; // id of index this table #endregion Fields #region Constructors /** * Constructor declaration * * * @param r * @param in * @param id */ 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 (Trace.ASSERT) { Trace.assert(iBalance != -2); } }
/** * remove method declaration * <P>This method is used to remove Rows from the Cache. It is called * by the cleanUp method. * * @param r (Row to be removed) * * @throws Exception */ private void remove(Row r) { if (Trace.ASSERT) { Trace.assert(!r.bChanged); // make sure rLastChecked does not point to r } if (r == rLastChecked) { rLastChecked = rLastChecked.rNext; if (rLastChecked == r) { rLastChecked = null; } } // make sure rData[k] does not point here int k = r.iPos & MASK; if (rData[k] == r) { Row n = r.rNext; rFirst = n; if (n == r || (n.iPos & MASK) != k) { n = null; } rData[k] = n; } // make sure rFirst does not point here if (r == rFirst) { rFirst = rFirst.rNext; if (r == rFirst) { rFirst = null; } } r.free(); iCacheSize--; }
/** * getWorst method declaration * <P>This method finds the Row with the smallest (oldest) iLastAccess member. * Called by the cleanup method. * * @return The selected Row object * * @throws Exception */ private Row getWorst() { if (rLastChecked == null) { rLastChecked = rFirst; } Row r = rLastChecked; if (r == null) { return null; } Row candidate = r; int worst = Row.iCurrentAccess; // algorithm: check the next rows and take the worst for (int i = 0; i < 6; i++) { int w = r.iLastAccess; if (w < worst) { candidate = r; worst = w; } r = r.rNext; } rLastChecked = r.rNext; return candidate; }
/** * Method declaration * * * @param w * @param a * @param b */ private static void swap(Row[] w, int a, int b) { Row t = w[a]; w[a] = w[b]; w[b] = t; }
/** * Method declaration * * * @param w * @param l * @param r * * @throws Exception */ 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].iPos > w[r].iPos) { swap(w, l, r); } if (w[i].iPos < w[l].iPos) { swap(w, l, i); } else if (w[i].iPos > w[r].iPos) { swap(w, i, r); } j = r - 1; swap(w, i, j); p = w[j].iPos; i = l; while (true) { if (Trace.STOP) { Trace.stop(); } while (w[++i].iPos < p); while (w[--j].iPos > 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 (Trace.STOP) { Trace.stop(); } Row t = w[i]; for (j = i - 1; j >= l && w[j].iPos > t.iPos; j--) { w[j + 1] = w[j]; } w[j + 1] = t; } }
/** * getRow method declaration * <P>This method reads a Row object from the cache. * * @param pos (offset of the requested Row in the cache) * @param t (Table this Row belongs to) * * @return The Row object as read from the cache. * * @throws Exception */ public Row getRow(int pos, Table t) { int k = pos & MASK; Row r = rData[k]; Row start = r; while (r != null) { if (Trace.STOP) { Trace.stop(); } int p = r.iPos; if (p == pos) { return r; } else if ((p & MASK) != k) { break; } r = r.rNext; if (r == start) { break; } } Row before = rData[k]; if (before == null) { before = rFirst; } try { rFile.Seek(pos,SeekOrigin.Begin); BinaryReader b = new BinaryReader(rFile); int size = b.ReadInt32(); byte[] buffer = new byte[size]; buffer = b.ReadBytes(size); MemoryStream bin = new MemoryStream(buffer); BinaryReader din = new BinaryReader(bin); r = new Row(t, din, pos, before); r.iSize = size; } catch (IOException e) { Console.WriteLine(e.StackTrace); throw Trace.error(Trace.FILE_IO_ERROR, "reading: " + e); } // todo: copy & paste here iCacheSize++; rData[k] = r; rFirst = r; return r; }
/** * free method declaration * <P>This method marks space in the database file as free. * <P><B>Note: </B>If more than MAX_FREE_COUNT free positios then * they are probably all are too small anyway; so we start a new list * <P>todo: This is wrong when deleting lots of records * * @param r (Row object to be marked free) * @param pos (Offset in the file this Row was stored at) * @param length (Size of the Row object to free) * * @throws Exception */ public void free(Row r, int pos, int length) { iFreeCount++; CacheFree n = new CacheFree(); n.iPos = pos; n.iLength = length; if (iFreeCount > MAX_FREE_COUNT) { iFreeCount = 0; } else { n.fNext = fRoot; } fRoot = n; // it's possible to remove roots to remove(r); }
/** * add method declaration * <P>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. * * @param r (Row to be added to Cache) * * @throws Exception */ public void add(Row r) { int size = r.iSize; CacheFree f = fRoot; CacheFree last = null; int i = iFreePos; while (f != null) { if (Trace.TRACE) { Trace.stop(); } // first that is long enough if (f.iLength >= size) { i = f.iPos; size = f.iLength - size; if (size < 8) { // remove almost empty blocks if (last == null) { fRoot = f.fNext; } else { last.fNext = f.fNext; } iFreeCount--; } else { f.iLength = size; f.iPos += r.iSize; } break; } last = f; f = f.fNext; } r.iPos = i; if (i == iFreePos) { iFreePos += size; } int k = i & MASK; Row before = rData[k]; if (before == null) { before = rFirst; } r.insert(before); iCacheSize++; rData[k] = r; rFirst = r; }
/** * Constructor declaration * * * @param r * @param id */ public Node(Row r, int id) { iId = id; rData = r; }
/** * Method declaration * * * @param row * @param c * @param log * * @throws Exception */ public void insertNoCheck(object[] row, Channel c, bool log) { int i; if (iIdentityColumn != -1) { if (row[iIdentityColumn] == null) { if (c != null) { c.setLastIdentity(iIdentityId); } row[iIdentityColumn] = iIdentityId++; } else { i = (int) row[iIdentityColumn]; if (iIdentityId <= i) { if (c != null) { c.setLastIdentity(i); } iIdentityId = i + 1; } } } for (i = 0; i < iColumnCount; i++) { if (row[i] == null &&!getColumn(i).isNullable()) { throw Trace.error(Trace.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)); } }
/** * Method declaration * * * @param before */ public void insert(Row before) { if (before == null) { rNext = this; rLast = this; } else { rNext = before; rLast = before.rLast; before.rLast = this; rLast.rNext = this; } }
/** * Method declaration * * * @throws Exception */ public void free() { rLast.rNext = rNext; rNext.rLast = rLast; if (rNext == this) { rNext = rLast = null; } }
// if read from cache /** * Constructor declaration * * * @param t * @param in * @param pos * @param before */ public Row(Table t, BinaryReader din, int pos, Row before) { tTable = t; int index = tTable.getIndexCount(); iPos = 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.getInternalColumnCount(); oData = Column.readData(din, l); int iCurrent = din.ReadInt32(); Trace.check(iCurrent == iPos, Trace.INPUTSTREAM_ERROR); insert(before); iLastAccess = iCurrentAccess++; }