Skip to content

Commit

Permalink
history - speed up resolving all history entries
Browse files Browse the repository at this point in the history
  • Loading branch information
bpasero committed Mar 18, 2022
1 parent a3ba1d3 commit ff45bb2
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,3 +125,10 @@ export interface IWorkingCopyHistoryService {
*/
removeAll(token: CancellationToken): Promise<void>;
}

/**
* A limit on how many I/O operations we allow to run in parallel.
* We do not want to spam the file system with too many requests
* at the same time, so we limit to a maximum degree of parallellism.
*/
export const MAX_PARALLEL_HISTORY_IO_OPS = 20;
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@
*--------------------------------------------------------------------------------------------*/

import { localize } from 'vs/nls';
import { Emitter } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { WorkingCopyHistoryTracker } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryTracker';
import { Disposable } from 'vs/base/common/lifecycle';
import { IWorkingCopyHistoryEntry, IWorkingCopyHistoryEntryDescriptor, IWorkingCopyHistoryEvent, IWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
import { IWorkingCopyHistoryEntry, IWorkingCopyHistoryEntryDescriptor, IWorkingCopyHistoryEvent, IWorkingCopyHistoryService, MAX_PARALLEL_HISTORY_IO_OPS } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
import { FileOperationError, FileOperationResult, IFileService, IFileStatWithMetadata } from 'vs/platform/files/common/files';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
import { URI } from 'vs/base/common/uri';
import { DeferredPromise } from 'vs/base/common/async';
import { DeferredPromise, Limiter } from 'vs/base/common/async';
import { extname, isEqual, joinPath } from 'vs/base/common/resources';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { hash } from 'vs/base/common/hash';
Expand Down Expand Up @@ -507,21 +507,29 @@ export abstract class WorkingCopyHistoryService extends Disposable implements IW
try {
const resolvedHistoryHome = await this.fileService.resolve(historyHome);
if (resolvedHistoryHome.children) {
const limiter = new Limiter(MAX_PARALLEL_HISTORY_IO_OPS);

for (const child of resolvedHistoryHome.children) {
if (token.isCancellationRequested) {
break;
}
limiter.queue(async () => {
if (token.isCancellationRequested) {
return;
}

const entriesFile = joinPath(child.resource, WorkingCopyHistoryModel.ENTRIES_FILE);
const entriesFile = joinPath(child.resource, WorkingCopyHistoryModel.ENTRIES_FILE);

try {
const serializedModel: ISerializedWorkingCopyHistoryModel = JSON.parse((await this.fileService.readFile(entriesFile)).value.toString());
if (serializedModel.entries.length > 0) {
all.set(URI.parse(serializedModel.resource), true);
try {
const serializedModel: ISerializedWorkingCopyHistoryModel = JSON.parse((await this.fileService.readFile(entriesFile)).value.toString());
if (serializedModel.entries.length > 0) {
all.set(URI.parse(serializedModel.resource), true);
}
} catch (error) {
// ignore - model might be missing or corrupt, but we need it
}
} catch (error) {
// ignore - model might be missing or corrupt, but we need it
}
});
}

if (limiter.size > 0) {
await Event.toPromise(limiter.onFinished);
}
}
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,20 @@ import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { isStoredFileWorkingCopySaveEvent, IStoredFileWorkingCopyModel } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopy';
import { IStoredFileWorkingCopySaveEvent } from 'vs/workbench/services/workingCopy/common/storedFileWorkingCopyManager';
import { IWorkingCopy } from 'vs/workbench/services/workingCopy/common/workingCopy';
import { IWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
import { IWorkingCopyHistoryService, MAX_PARALLEL_HISTORY_IO_OPS } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
import { IWorkingCopySaveEvent, IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService';
import { Schemas } from 'vs/base/common/network';

export class WorkingCopyHistoryTracker extends Disposable implements IWorkbenchContribution {

// Adding history entries from the tracker should not be
// an operation that should be unbounded and as such we
// limit the write operations up to a maximum degree.
private static readonly MAX_PARALLEL_HISTORY_WRITES = 10;

private static readonly SETTINGS = {
ENABLED: 'workbench.localHistory.enabled',
SIZE_LIMIT: 'workbench.localHistory.maxFileSize',
};

private static readonly UNDO_REDO_SAVE_SOURCE = SaveSourceRegistry.registerSource('undoRedo.source', localize('undoRedo.source', "Undo / Redo"));

private readonly limiter = this._register(new Limiter(WorkingCopyHistoryTracker.MAX_PARALLEL_HISTORY_WRITES));
private readonly limiter = this._register(new Limiter(MAX_PARALLEL_HISTORY_IO_OPS));

private readonly pendingAddHistoryEntryOperations = new ResourceMap<CancellationTokenSource>(resource => this.uriIdentityService.extUri.getComparisonKey(resource));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { WorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistoryService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IWorkingCopyHistoryService } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';
import { IWorkingCopyHistoryService, MAX_PARALLEL_HISTORY_IO_OPS } from 'vs/workbench/services/workingCopy/common/workingCopyHistory';

export class NativeWorkingCopyHistoryService extends WorkingCopyHistoryService {

Expand All @@ -42,7 +42,7 @@ export class NativeWorkingCopyHistoryService extends WorkingCopyHistoryService {

// Prolong shutdown for orderly model shutdown
e.join((async () => {
const limiter = new Limiter(20); // prevent too many IO-ops running in parallel
const limiter = new Limiter(MAX_PARALLEL_HISTORY_IO_OPS);

const models = Array.from(this.models.values());
for (const model of models) {
Expand Down

0 comments on commit ff45bb2

Please sign in to comment.