public RowEnumerator(TableSnapshot <TRecord> table) { this.table = table; this.version = this.table.StoreSnapshot.Version; this.count = this.table.table.Count(this.version); this.index = -1; }
/// <summary> /// Pushes row to log. Row can be logged only once in transaction, so only initial state (as it was at the beginning of transaction) will be saved /// </summary> /// <param name="row">Reference to the data to be logged</param> /// <param name="rowId">Id of this data. This should be the Id of row provided in the first param.</param> private void PushToLog(ref Row row, RowId rowId) { // ref to row should be in table at rowId. It is impossible to check this in C#, so just check if bits are equal Debug.Assert( 0 == TableSnapshot <TRecord> .Compare( this.Fields, ref row.Data, ref this.table.ItemAddress(rowId.Value).Page[this.table.ItemAddress(rowId.Value).Index].Data ), "ref to row should be in table at rowId" ); ValueList <Snap> .Address snapAddress = this.snap.ItemAddress(this.snap.Count - 1); if (snapAddress.Page[snapAddress.Index].Version < this.SnapStore.Version) { // first change in this transaction so the row is older Debug.Assert(rowId.Value < snapAddress.Page[snapAddress.Index].TableSize, "Row should be already in the table"); this.snap.PrepareAdd(); this.log.PrepareAdd(); Snap point = new Snap() { Version = this.SnapStore.Version, TableSize = this.table.Count, LogSize = this.log.Count + 1 }; RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { int index = this.log.FixedAllocate(); ValueList <Log> .Address logAddress = this.log.ItemAddress(index); logAddress.Page[logAddress.Index].Data = row.Data; logAddress.Page[logAddress.Index].RowId = rowId; logAddress.Page[logAddress.Index].RawLogIndex = row.RawLogIndex; row.LogIndex = index; this.snap.FixedAdd(ref point); } } else { Debug.Assert(snapAddress.Page[snapAddress.Index].Version == this.SnapStore.Version, "Impossible state: this should be the current transaction"); Debug.Assert(snapAddress.Page[snapAddress.Index].TableSize == this.table.Count, "Impossible state: wrong table size"); Debug.Assert(snapAddress.Page[snapAddress.Index].LogSize == this.log.Count, "Impossible state: wrong log size"); // some changes were made in this transaction. Check if the row was already modified in this transaction. // get size of log in the previous transaction ValueList <Snap> .Address oldSnapAddress = this.snap.ItemAddress(this.snap.Count - 2); if (rowId.Value < oldSnapAddress.Page[oldSnapAddress.Index].TableSize && row.LogIndex < oldSnapAddress.Page[oldSnapAddress.Index].LogSize) { // this is the first time the row is updated in this transaction Debug.Assert(snapAddress.Page[snapAddress.Index].LogSize == this.log.Count, "Invalid state: wrong log size"); this.log.PrepareAdd(); RuntimeHelpers.PrepareConstrainedRegions(); try {} finally { int index = this.log.FixedAllocate(); ValueList <Log> .Address logAddress = this.log.ItemAddress(index); logAddress.Page[logAddress.Index].Data = row.Data; logAddress.Page[logAddress.Index].RowId = rowId; logAddress.Page[logAddress.Index].RawLogIndex = row.RawLogIndex; row.LogIndex = index; snapAddress.Page[snapAddress.Index].LogSize = this.log.Count; } } } }
public ChangeEnumerator(TableSnapshot <TRecord> table, List <int> version) { // assuming version is sorted this.table = table.table; this.newVersion = version[version.Count - 1]; this.oldVersion = version[0]; this.MergeChanges(version); this.enumerator = this.action.GetEnumerator(); }
public ForeignKey( string name, IUniqueIndex <TField> primaryKey, TableSnapshot <TRecord> childTable, IField <TRecord, TField> childColumn, ForeignKeyAction action, bool allowsDefault ) { this.Name = name; this.primaryKey = primaryKey; this.childTable = childTable; this.childColumn = childColumn; this.action = action; this.allowsDefault = allowsDefault; }
/// <summary> /// Sets entire structure. /// </summary> /// <param name="rowId"></param> /// <param name="data"></param> /// <returns></returns> public bool SetData(RowId rowId, ref TRecord data) { Debug.Assert(0 <= rowId.Value && rowId.Value < this.table.Count, "broken rowId"); this.ValidateModification(); ValueList <Row> .Address address = this.table.ItemAddress(rowId.Value); SnapTable <TRecord> .ValidateModification(ref address); if (TableSnapshot <TRecord> .Compare(this.Fields, ref address.Page[address.Index].Data, ref data) != 0) { this.PushToLog(ref address.Page[address.Index], rowId); address.Page[address.Index].Data = data; Debug.Assert(TableSnapshot <TRecord> .Compare(this.Fields, ref address.Page[address.Index].Data, ref data) == 0, "Assignment or comparison failed"); return(true); } return(false); }
private void DeleteRow(RowId rowId) { int timestamp = TableSnapshot <TRecord> .Timestamp(); foreach (List <IIndex <TRecord> > list in this.table.Indexes) { if (list != null) { foreach (IIndex <TRecord> index in list) { if (index.Timestamp != timestamp) { index.Delete(rowId); index.Timestamp = timestamp; } } } } this.table.Delete(rowId); }
/// <summary> /// Checks if table is empty i.e. no records exist. /// </summary> /// <returns></returns> public bool IsEmpty() { foreach (List <IIndex <TRecord> > list in this.table.Indexes) { if (list != null && 0 < list.Count) { foreach (IIndex <TRecord> index in list) { return(index.IsEmpty(this.StoreSnapshot.Version)); } } } if (this.table.PrimaryKey != null) { // No real index were found. The only hope is pseudo unique index of primary key. // Right now it is not faster then just table scan, but anyway use it as in the future it may change. return(this.table.PrimaryKey.IsEmpty(this.StoreSnapshot.Version)); } // There is no indexes on the table. Do a full scan. return(TableSnapshot <TRecord> .IsEmpty(this.table, this.StoreSnapshot.Version)); }
public RowId Insert(ref TRecord data) { this.ValidateModification(); RowId rowId = this.table.Insert(ref data); int timestamp = TableSnapshot <TRecord> .Timestamp(); foreach (List <IIndex <TRecord> > list in this.table.Indexes) { if (list != null) { foreach (IIndex <TRecord> index in list) { if (index.Timestamp != timestamp) { index.Insert(rowId); index.Timestamp = timestamp; } } } } return(rowId); }
public bool IsEmpty(int version) { return(TableSnapshot <TRecord> .IsEmpty(this.table, version)); }
public RolledBackChangesEnumerator(TableSnapshot <TRecord> table, int version) { this.enumerator = table.table.GetRolledBackChanges(version); }