Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(340)

Unified Diff: web/inc/logdog-stream-view/viewer.ts

Issue 2861583003: Enable sequential prefix index logs to be loaded. (Closed)
Patch Set: comments Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: web/inc/logdog-stream-view/viewer.ts
diff --git a/web/inc/logdog-stream-view/viewer.ts b/web/inc/logdog-stream-view/viewer.ts
index c2b6b20d9ac72e45e8b09418763e5301d4dcece0..609eb1ba55835799f81bb0b32bc5748bb25d1923 100644
--- a/web/inc/logdog-stream-view/viewer.ts
+++ b/web/inc/logdog-stream-view/viewer.ts
@@ -1023,6 +1023,62 @@ namespace LogDog {
}
/**
+ * LogSorter is an interface that used by AggregateLogStream to extract sorted
+ * logs from a set of BufferedLogs.
+ *
+ * It is used to compare two log entries to determine their relative order.
+ */
+ type LogSorter = {
+ /** Returns true if "a" comes before "b". */
+ before: (a: LogDog.LogEntry, b: LogDog.LogEntry) => number;
+
+ /**
+ * If implemented, returns an implicit next log in the buffer set.
+ *
+ * This is useful if the next log can be determined from the current
+ * buffered data, even if it is partial or incomplete.
+ */
+ implicitNext?: (prev: LogDog.LogEntry, buffers: BufferedLogs[]) =>
+ LogDog.LogEntry | null;
+ };
+
+ const prefixIndexLogSorter: LogSorter = {
+ before: (a: LogDog.LogEntry, b: LogDog.LogEntry) => {
+ return (a.prefixIndex - b.prefixIndex);
+ },
+
+ implicitNext: (prev: LogDog.LogEntry, buffers: BufferedLogs[]) => {
+ let nextPrefixIndex = (prev.prefixIndex + 1);
+ for (let buf of buffers) {
+ let le = buf.peek();
+ if (le && le.prefixIndex === nextPrefixIndex) {
+ return buf.next();
+ }
+ }
+ return null;
+ },
+ };
+
+ const timestampLogSorter: LogSorter = {
+ before: (a: LogDog.LogEntry, b: LogDog.LogEntry) => {
+ if (a.timestamp) {
+ if (b.timestamp) {
+ return a.timestamp.getTime() - b.timestamp.getTime();
+ }
+ return 1;
+ }
+ if (b.timestamp) {
+ return -1;
+ }
+ return 0;
+ },
+
+ // No implicit "next" with timestamp-based logs, since the next log in
+ // an empty buffer may actually be the next contiguous log.
+ implicitNext: undefined,
+ };
+
+ /**
* An aggregate log stream. It presents a single-stream view, but is really
* composed of several log streams interleaved based on their prefix indices
* (if they share a prefix) or timestamps (if they don't).
@@ -1039,7 +1095,7 @@ namespace LogDog {
private streams: AggregateLogStream.Entry[];
private active: AggregateLogStream.Entry[];
private currentNextPromise: Promise<BufferedLogs[]>|null;
- private compareLogs: (a: LogDog.LogEntry, b: LogDog.LogEntry) => number;
+ private readonly logSorter: LogSorter;
private streamStatusCallback: StreamStatusCallback;
@@ -1074,20 +1130,11 @@ namespace LogDog {
return template.samePrefixAs(entry.ls.stream);
});
- this.compareLogs = ((sharedPrefix) ? (a, b) => {
- return (a.prefixIndex - b.prefixIndex);
- } : (a, b) => {
- if (a.timestamp) {
- if (b.timestamp) {
- return a.timestamp.getTime() - b.timestamp.getTime();
- }
- return 1;
- } else if (b.timestamp) {
- return -1;
- } else {
- return 0;
- }
- });
+ if (sharedPrefix) {
+ this.logSorter = prefixIndexLogSorter;
+ } else {
+ this.logSorter = timestampLogSorter;
+ }
}
split(): SplitLogProvider|null {
@@ -1223,7 +1270,6 @@ namespace LogDog {
// its entries are sorted, then that buffer is a return value.
return new BufferedLogs(buffers[0].getAll());
default:
- // Nothing to do.
break;
}
@@ -1240,12 +1286,16 @@ namespace LogDog {
}
// Assemble our aggregate buffer array.
+ //
+ // As we add log entries, latestAdded will be updated to point to the most
+ // recently added LogEntry.
let entries: LogDog.LogEntry[] = [];
+ let latestAdded: LogDog.LogEntry|null = null;
while (true) {
// Choose the next stream.
let earliest = 0;
for (let i = 1; i < buffers.length; i++) {
- if (this.compareLogs(peek[i], peek[earliest]) < 0) {
+ if (this.logSorter.before(peek[i], peek[earliest])) {
earliest = i;
}
}
@@ -1253,17 +1303,31 @@ namespace LogDog {
// Get the next log from the earliest stream.
let next = buffers[earliest].next();
if (next) {
- entries.push(next);
+ latestAdded = next;
+ entries.push(latestAdded);
}
// Repopulate that buffer's "peek" value. If the buffer has no more
- // entries, then we're done.
+ // entries, then we're done this round.
next = buffers[earliest].peek();
if (!next) {
- return new BufferedLogs(entries);
+ break;
}
peek[earliest] = next;
}
+
+ // One or more of our buffers is exhausted. If we have the ability to load
+ // implicit next logs, try and extract more using that.
+ if (latestAdded && this.logSorter.implicitNext) {
+ while (true) {
+ latestAdded = this.logSorter.implicitNext(latestAdded, buffers);
+ if (!latestAdded) {
+ break;
+ }
+ entries.push(latestAdded);
+ }
+ }
+ return new BufferedLogs(entries);
}
}
@@ -1325,6 +1389,14 @@ namespace LogDog {
}
/**
+ * Returns a copy of the remaining logs in the buffer.
+ * If there are no logs, an empty array will be returned.
+ */
+ peekAll(): LogDog.LogEntry[] {
+ return (this.logs || []).slice(0);
+ }
+
+ /**
* GetAll returns all logs in the buffer. Afterwards, the buffer will be
* empty.
*/
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698