ProjectionVersions GetProjectionVersions(string contractId) { ProjectionVersions versions = inMemoryVersionStore.Get(contractId); if (versions == null || versions.Count == 0) { var versionId = new ProjectionVersionManagerId(contractId); var persistentVersionType = typeof(PersistentProjectionVersionHandler); var persistentVersionContractId = persistentVersionType.GetContractId(); var persistentVersion = new ProjectionVersion(persistentVersionContractId, ProjectionStatus.Live, 1, persistentVersionType.GetProjectionHash()); ProjectionStream stream = LoadProjectionStream(typeof(PersistentProjectionVersionHandler), persistentVersion, versionId, new NoSnapshot(versionId, contractId)); var queryResult = stream.RestoreFromHistory <PersistentProjectionVersionHandler>(); if (queryResult.Success) { if (queryResult.Projection.State.Live != null) { inMemoryVersionStore.Cache(queryResult.Projection.State.Live); } if (queryResult.Projection.State.Building != null) { inMemoryVersionStore.Cache(queryResult.Projection.State.Building); } versions = inMemoryVersionStore.Get(contractId); } // inception if (versions == null || versions.Count == 0) { if (string.Equals(persistentVersionContractId, contractId, StringComparison.OrdinalIgnoreCase)) { inMemoryVersionStore.Cache(persistentVersion); versions = inMemoryVersionStore.Get(contractId); } else { var initialVersion = new ProjectionVersion(contractId, ProjectionStatus.Building, 1, contractId.GetTypeByContract().GetProjectionHash()); inMemoryVersionStore.Cache(initialVersion); versions = inMemoryVersionStore.Get(contractId); } } } return(versions ?? new ProjectionVersions()); }
public IProjectionGetResult <T> Get <T>(IBlobId projectionId) where T : IProjectionDefinition { try { Type projectionType = typeof(T); string contractId = projectionType.GetContractId(); ProjectionVersion liveVersion = GetProjectionVersions(contractId).GetLive(); ISnapshot snapshot = snapshotStore.Load(contractId, projectionId, liveVersion); ProjectionStream stream = LoadProjectionStream(projectionType, liveVersion, projectionId, snapshot); IProjectionGetResult <T> queryResult = stream.RestoreFromHistory <T>(); return(queryResult); } catch (Exception ex) { log.ErrorException(ex.Message, ex); return(new ProjectionGetResult <T>(default(T))); } }
ProjectionStream LoadProjectionStream(Type projectionType, ProjectionVersion projectionVersion, IBlobId projectionId, ISnapshot snapshot) { ISnapshot currentSnapshot = snapshot; string contractId = projectionVersion.ProjectionContractId; List <ProjectionCommit> projectionCommits = new List <ProjectionCommit>(); int snapshotMarker = snapshot.Revision; while (true) { snapshotMarker++; var loadedCommits = projectionStore.Load(projectionVersion, projectionId, snapshotMarker).ToList(); if (loadedCommits.Count > 1000) { log.Warn($"Potential memory leak. The system will be down fairly soon. The projection `{contractId}` for id={projectionId} loads a lot of projection commits ({loadedCommits.Count}) and snapshot `{snapshot.GetType().Name}` which puts a lot of CPU and RAM pressure. You can resolve this by enabling the Snapshots feature in the host which handles projection WRITES and READS using `.UseSnapshots(...)`."); } projectionCommits.AddRange(loadedCommits); bool isSnapshotable = typeof(IAmNotSnapshotable).IsAssignableFrom(projectionType) == false; if (isSnapshotable && snapshotStrategy.ShouldCreateSnapshot(projectionCommits, snapshot.Revision)) { ProjectionStream checkpointStream = new ProjectionStream(projectionId, projectionCommits, currentSnapshot); var projectionState = checkpointStream.RestoreFromHistory(projectionType).Projection.State; ISnapshot newSnapshot = new Snapshot(projectionId, contractId, projectionState, snapshot.Revision + 1); snapshotStore.Save(newSnapshot, projectionVersion); currentSnapshot = newSnapshot; projectionCommits.Clear(); } else if (loadedCommits.Count() < snapshotStrategy.EventsInSnapshot) { break; } } ProjectionStream stream = new ProjectionStream(projectionId, projectionCommits, currentSnapshot); return(stream); }