public ContentStore(IPublishedSnapshotAccessor publishedSnapshotAccessor, IVariationContextAccessor variationContextAccessor, ILogger logger, BPlusTree <int, ContentNodeKit> localDb = null) { _publishedSnapshotAccessor = publishedSnapshotAccessor; _variationContextAccessor = variationContextAccessor; _logger = logger; _localDb = localDb; _contentNodes = new ConcurrentDictionary <int, LinkedNode <ContentNode> >(); _contentRootNodes = new ConcurrentDictionary <int, LinkedNode <object> >(); _contentTypesById = new ConcurrentDictionary <int, LinkedNode <PublishedContentType> >(); _contentTypesByAlias = new ConcurrentDictionary <string, LinkedNode <PublishedContentType> >(StringComparer.InvariantCultureIgnoreCase); _xmap = new ConcurrentDictionary <Guid, int>(); _genRefRefs = new ConcurrentQueue <GenRefRef>(); _genRefRef = null; // no initial gen exists _liveGen = _floorGen = 0; _nextGen = false; // first time, must create a snapshot _collectAuto = true; // collect automatically by default }
public Snapshot CreateSnapshot() { var lockInfo = new ReadLockInfo(); try { Lock(lockInfo); // if no next generation is required, and we already have one, // use it and create a new snapshot if (_nextGen == false && _genRefRef != null) { return(new Snapshot(this, _genRefRef.GetGenRef() #if DEBUG , _logger #endif )); } // else we need to try to create a new gen ref // whether we are wlocked or not, noone can rlock while we do, // so _liveGen and _nextGen are safe if (_wlocked > 0) // volatile, cannot ++ but could -- { // write-locked, cannot use latest gen (at least 1) so use previous var snapGen = _nextGen ? _liveGen - 1 : _liveGen; // create a new gen ref unless we already have it if (_genRefRef == null) { _genRefRefs.Enqueue(_genRefRef = new GenRefRef(snapGen)); } else if (_genRefRef.Gen != snapGen) { throw new Exception("panic"); } } else { // not write-locked, can use latest gen, create a new gen ref _genRefRefs.Enqueue(_genRefRef = new GenRefRef(_liveGen)); _nextGen = false; // this is the ONLY thing that triggers a _liveGen++ } // so... // the genRefRef has a weak ref to the genRef, and is queued // the snapshot has a ref to the genRef, which has a ref to the genRefRef // when the snapshot is disposed, it decreases genRefRef counter // so after a while, one of these conditions is going to be true: // - the genRefRef counter is zero because all snapshots have properly been disposed // - the genRefRef weak ref is dead because all snapshots have been collected // in both cases, we will dequeue and collect var snapshot = new Snapshot(this, _genRefRef.GetGenRef() #if DEBUG , _logger #endif ); // reading _floorGen is safe if _collectTask is null if (_collectTask == null && _collectAuto && _liveGen - _floorGen > CollectMinGenDelta) { CollectAsyncLocked(); } return(snapshot); } finally { Release(lockInfo); } }
public GenRef(GenRefRef genRefRef, long gen) { GenRefRef = genRefRef; Gen = gen; }