public void ReadToEnd() { WithVolumeHandle( volumeHandle => { byte[] buffer = new byte[4096]; while (true) { QueryUsnJournalData journalState = QueryJournal(volumeHandle); ReadUsnJournalResult readJournalResult = FileUtilities.TryReadUsnJournal( volumeHandle, buffer, journalState.UsnJournalId, startUsn: journalState.NextUsn); XAssert.AreEqual(ReadUsnJournalStatus.Success, readJournalResult.Status); XAssert.IsFalse(readJournalResult.NextUsn.IsZero); XAssert.IsTrue(readJournalResult.NextUsn >= journalState.NextUsn); if (readJournalResult.Records.Count == 0) { break; } } }); }
public void ReadEarliestUsnRecords() { WithVolumeHandle( volumeHandle => { QueryUsnJournalData journalState = QueryJournal(volumeHandle); byte[] buffer = new byte[4096]; ReadUsnJournalResult readJournalResult = FileUtilities.TryReadUsnJournal(volumeHandle, buffer, journalState.UsnJournalId, startUsn: new Usn(0)); XAssert.AreEqual(ReadUsnJournalStatus.Success, readJournalResult.Status); XAssert.IsFalse(readJournalResult.NextUsn.IsZero); XAssert.IsTrue(readJournalResult.NextUsn >= journalState.FirstUsn); XAssert.AreNotEqual(0, readJournalResult.Records.Count, "It is unlikely that this journal should be empty, since this test's execution has written to the volume."); var firstRecord = readJournalResult.Records.First(); XAssert.IsTrue(firstRecord.Usn == journalState.FirstUsn); XAssert.IsTrue(firstRecord.Usn < readJournalResult.NextUsn); var lastUsn = firstRecord.Usn; foreach (UsnRecord record in readJournalResult.Records.Skip(1)) { XAssert.IsTrue(record.Usn > lastUsn, "Expected USNs to be monotically increasing."); lastUsn = record.Usn; XAssert.IsTrue(record.Usn >= journalState.FirstUsn); XAssert.IsTrue(record.Usn < readJournalResult.NextUsn); } }); }
private void ExpectChangesSinceUsn( UsnChangeReasons expectedChangeReasons, SafeFileHandle volumeHandle, Usn startUsn, FileId fileId, out Usn nextUsn, TimeSpan?timeLimit = default(TimeSpan?)) { const int DefaultTimeLimitForScanningInSecond = 30; // 30 sec for scanning. QueryUsnJournalData journalState = QueryJournal(volumeHandle); byte[] buffer = new byte[64 * 1024]; // 655 records per read. timeLimit = timeLimit.HasValue ? timeLimit : TimeSpan.FromSeconds(DefaultTimeLimitForScanningInSecond); var stopWatch = System.Diagnostics.Stopwatch.StartNew(); UsnChangeReasons foundChangeReasons = 0; nextUsn = startUsn; while (true) { if (stopWatch.ElapsedTicks > timeLimit.Value.Ticks) { break; } ReadUsnJournalResult result = FileUtilities.TryReadUsnJournal( volumeHandle, buffer, journalState.UsnJournalId, startUsn); nextUsn = result.NextUsn; if (!result.Succeeded) { break; } if (result.Records.Count == 0) { break; } foundChangeReasons |= UsnJournalUtilities.GetAggregateChangeReasons(fileId, result.Records); if (expectedChangeReasons == (foundChangeReasons & expectedChangeReasons)) { // Found all expected change reasons. return; } startUsn = result.NextUsn; } XAssert.AreEqual(expectedChangeReasons, foundChangeReasons & expectedChangeReasons); }
private ReadUsnJournalResult ReadChangesSinceUsn(SafeFileHandle volumeHandle, Usn startUsn) { QueryUsnJournalData journalState = QueryJournal(volumeHandle); // TODO: On a busy volume, we may need to read up to a particular expected USN - or we will fill up the single buffer before finding the expected records. byte[] buffer = new byte[32768]; ReadUsnJournalResult readJournalResult = FileUtilities.TryReadUsnJournal(volumeHandle, buffer, journalState.UsnJournalId, startUsn: startUsn); XAssert.AreEqual(ReadUsnJournalStatus.Success, readJournalResult.Status); return(readJournalResult); }
/// <inheritdoc /> public MaybeResponse <ReadJournalResponse> ReadJournal(ReadJournalRequest request, Action <UsnRecord> onUsnRecordReceived) { Contract.Assert(request.VolumeGuidPath.IsValid); SafeFileHandle volumeHandle; OpenFileResult volumeOpenResult = OpenVolumeHandle(request.VolumeGuidPath, out volumeHandle); using (volumeHandle) { if (!volumeOpenResult.Succeeded) { string message = I($"Failed to open a volume handle for the volume '{request.VolumeGuidPath.Path}'"); return(new MaybeResponse <ReadJournalResponse>( new ErrorResponse(ErrorStatus.FailedToOpenVolumeHandle, message))); } Usn startUsn = request.StartUsn; Usn endUsn = request.EndUsn ?? Usn.Zero; int extraReadCount = request.ExtraReadCount ?? -1; long timeLimitInTicks = request.TimeLimit?.Ticks ?? -1; var sw = new StopwatchVar(); using (var swRun = sw.Start()) { byte[] buffer = new byte[JournalReadBufferSize]; while (true) { if (timeLimitInTicks >= 0 && timeLimitInTicks < swRun.ElapsedTicks) { return(new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: startUsn, timeout: true))); } ReadUsnJournalResult result = FileUtilities.TryReadUsnJournal( volumeHandle, buffer, request.JournalId, startUsn, isJournalUnprivileged: IsJournalUnprivileged); if (!result.Succeeded) { // Bug #1164760 shows that the next USN can be non-zero. return(new MaybeResponse <ReadJournalResponse>(new ReadJournalResponse(status: result.Status, nextUsn: result.NextUsn))); } if (result.Records.Count == 0) { return (new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: result.NextUsn))); } foreach (var record in result.Records) { onUsnRecordReceived(record); } Contract.Assume(startUsn < result.NextUsn); startUsn = result.NextUsn; if (!endUsn.IsZero) { if (startUsn >= endUsn && (--extraReadCount) < 0) { return(new MaybeResponse <ReadJournalResponse>( new ReadJournalResponse(status: ReadUsnJournalStatus.Success, nextUsn: result.NextUsn))); } } } } } }