public void BuildCollect(TableKey tableKey, Transaction.RecordAccessed recordAccessed) { if (tableHasListener) { ChangeRecordCollector recordCollector = new ChangeRecordCollector(tableKey, table, recordAccessed); records.Add(tableKey.Key, recordCollector); } }
public void CollectChanged(TableKey tableKey, Collect collect) { if (tables.TryGetValue(tableKey.TableId, out var ctc)) { ctc.CollectChanged(tableKey, collect); } // else skip error 只有测试代码可能会走到这个分支。 }
public void BuildCollect(TableKey tableKey, Transaction.RecordAccessed recordAccessed) { if (false == tables.TryGetValue(tableKey.TableId, out var tableCollector)) { tableCollector = new ChangeTableCollector(tableKey); tables.Add(tableKey.TableId, tableCollector); } tableCollector.BuildCollect(tableKey, recordAccessed); }
public RootInfo CreateRootInfoIfNeed(TableKey tkey) { var cur = Value?.RootInfo; if (null == cur) { cur = new RootInfo(this, tkey); } return(cur); }
internal RecordAccessed GetRecordAccessed(TableKey key) { // 允许读取事务内访问过的记录。 //if (IsCompleted) // throw new Exception("Transaction Is Completed"); if (accessedRecords.TryGetValue(key, out var record)) { return(record); } return(null); }
public void CollectChanged(TableKey tableKey, ChangeCollector.Collect collect) { if (false == this.tableHasListener) { return; // 优化,表格没有监听者时,不收集改变。 } if (records.TryGetValue(tableKey.Key, out var crc)) { crc.CollectChanged(collect); } // else skip error . 只有测试代码可能会走到这个分支。 }
public ChangeRecordCollector(TableKey tableKey, Table table, Transaction.RecordAccessed recordAccessed) { this.recordAccessed = recordAccessed; key = tableKey.Key; // 记录发生了覆盖或者删除,也需要把listener建立好,以便后面Notify。但是就不需要收集log和note了。参见下面的 CollectChanged. Dictionary <int, HashSet <ChangeListener> > tmp = table.ChangeListenerMap.mapCopy; foreach (var e in tmp) { ChangeVariableCollector cvc = table.CreateChangeVariableCollector(e.Key); if (null != cvc) // 忽略掉不正确的 variableId,也许注册的时候加个检查更好,先这样了。 { variables.Add(e.Key, cvc); cvc.listeners = e.Value; } } }
// under lockey.writelock /* * internal bool RemoeIfNotDirty(K key) * { * var storage = Table.Storage; * if (null == storage) * return false; // 内存表不该发生Reduce. * * if (storage.IsRecordChanged(key)) // 在记录里面维持一个 Dirty 标志是可行的,但是由于 Cache.CleanNow 执行的不频繁,无所谓了。 * return false; * * return map.TryRemove(key, out var _); * } */ private bool TryRemoveRecord(KeyValuePair <K, Record <K, V> > p) { TableKey tkey = new TableKey(this.Table.Id, p.Key); Lockey lockey = Locks.Instance.Get(tkey); if (false == lockey.TryEnterWriteLock(0)) { return(false); } try { var storage = Table.Storage; if (null == storage) { /* 不支持内存表cache同步。 * if (p.Value.Acquire(GlobalCacheManager.StateInvalid) != GlobalCacheManager.StateInvalid) * return false; */ return(Remove(p)); } if (storage.IsRecordChanged(p.Key)) // 在记录里面维持一个 Dirty 标志是可行的,但是由于 Cache.CleanNow 执行的不频繁,无所谓了。 { return(false); } if (p.Value.State != GlobalCacheManager.StateInvalid) { if (p.Value.Acquire(GlobalCacheManager.StateInvalid) != GlobalCacheManager.StateInvalid) { return(false); } } return(Remove(p)); } finally { lockey.ExitWriteLock(); } }
private CheckResult _lock_and_check_() { if (savepoints.Count > 0) { // 全部 Rollback 时 Count 为 0;最后提交时 Count 必须为 1;其他情况属于Begin,Commit,Rollback不匹配。外面检查。 foreach (var log in savepoints[savepoints.Count - 1].Logs.Values) { if (log.Bean == null) { continue; // 特殊日志。不是 bean 的修改日志,当然也不会修改 Record。现在不会有这种情况,保留给未来扩展需要。 } TableKey tkey = log.Bean.TableKey; if (accessedRecords.TryGetValue(tkey, out var record)) { record.Dirty = true; } else { logger.Fatal("impossible! record not found."); // 只有测试代码会把非 Managed 的 Bean 的日志加进来。 } } } bool conflict = false; // 冲突了,也继续加锁,为重做做准备!!! if (holdLocks.Count == 0) { foreach (var e in accessedRecords) { switch (_lock_and_check_(e)) { case CheckResult.Success: break; case CheckResult.Redo: conflict = true; break; // continue lock case CheckResult.RedoAndReleaseLock: return(CheckResult.RedoAndReleaseLock); } } return(conflict ? CheckResult.Redo : CheckResult.Success); } int index = 0; int n = holdLocks.Count; foreach (var e in accessedRecords) { // 如果 holdLocks 全部被对比完毕,直接锁定它 if (index >= n) { switch (_lock_and_check_(e)) { case CheckResult.Success: break; case CheckResult.Redo: conflict = true; break; // continue lock case CheckResult.RedoAndReleaseLock: return(CheckResult.RedoAndReleaseLock); } continue; } Lockey curLock = holdLocks[index]; int c = curLock.TableKey.CompareTo(e.Key); // holdlocks a b ... // needlocks a b ... if (c == 0) { // 这里可能发生读写锁提升 if (e.Value.Dirty && false == curLock.isWriteLockHeld()) { curLock.EnterLock(true); switch (_check_(true, e.Value)) { case CheckResult.Success: break; case CheckResult.Redo: conflict = true; break; // continue lock case CheckResult.RedoAndReleaseLock: return(CheckResult.RedoAndReleaseLock); } } // else 已经持有读锁,不可能被修改也不可能降级(reduce),所以不做检测了。 // 已经锁定了,跳过 ++index; continue; } // holdlocks a b ... // needlocks a c ... if (c < 0) { // 释放掉 比当前锁序小的锁,因为当前事务中不再需要这些锁 int unlockEndIndex = index; for (; unlockEndIndex < n && holdLocks[unlockEndIndex].TableKey.CompareTo(e.Key) < 0; ++unlockEndIndex) { var toUnlockLocker = holdLocks[unlockEndIndex]; toUnlockLocker.ExitLock(); } holdLocks.RemoveRange(index, unlockEndIndex - index); n = holdLocks.Count; continue; } // holdlocks a c ... // needlocks a b ... // 为了不违背锁序,释放从当前锁开始的所有锁 for (int i = index; i < n; ++i) { var toUnlockLocker = holdLocks[i]; toUnlockLocker.ExitLock(); } holdLocks.RemoveRange(index, n - index); n = holdLocks.Count; } return(conflict ? CheckResult.Redo : CheckResult.Success); }
public bool Contains(TableKey tkey) { return(Contains(new Lockey(tkey))); }
public Lockey Get(TableKey tkey) { return(Get(new Lockey(tkey))); }
/// <summary> /// 相同值的 TableKey 要得到同一个 Lock 引用,必须使用 Locks 查询。 /// 不要自己构造这个对象。开放出去仅仅为了测试。 /// </summary> /// <param name="key"></param> public Lockey(TableKey key) { TableKey = key; }
public RootInfo(Record record, TableKey tableKey) { Record = record; TableKey = tableKey; }
public ChangeTableCollector(TableKey tableKey) { table = Table.GetTable(tableKey.TableId); tableHasListener = table.ChangeListenerMap.HasListener(); }