diff --git a/src/vs/base/test/node/pfs/pfs.test.ts b/src/vs/base/test/node/pfs/pfs.test.ts index 7a7ae068099..4f09ad2b56d 100644 --- a/src/vs/base/test/node/pfs/pfs.test.ts +++ b/src/vs/base/test/node/pfs/pfs.test.ts @@ -15,6 +15,7 @@ import { getPathFromAmdModule } from 'vs/base/common/amd'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { canNormalize } from 'vs/base/common/normalization'; +import { VSBuffer } from 'vs/base/common/buffer'; const chunkSize = 64 * 1024; const readError = 'Error while reading'; @@ -403,7 +404,7 @@ suite('PFS', () => { const smallData = 'Hello World'; const bigData = (new Array(100 * 1024)).join('Large String\n'); - return testWriteFileAndFlush(new TextEncoder().encode(smallData), smallData, new TextEncoder().encode(bigData), bigData); + return testWriteFileAndFlush(VSBuffer.fromString(smallData).buffer, smallData, VSBuffer.fromString(bigData).buffer, bigData); }); test('writeFile (stream)', async () => { diff --git a/src/vs/workbench/services/files2/common/fileService2.ts b/src/vs/workbench/services/files2/common/fileService2.ts index be3300f18f5..73133e55ceb 100644 --- a/src/vs/workbench/services/files2/common/fileService2.ts +++ b/src/vs/workbench/services/files2/common/fileService2.ts @@ -14,6 +14,7 @@ import { TernarySearchTree } from 'vs/base/common/map'; import { isNonEmptyArray, coalesce } from 'vs/base/common/arrays'; import { getBaseLabel } from 'vs/base/common/labels'; import { ILogService } from 'vs/platform/log/common/log'; +import { VSBuffer } from 'vs/base/common/buffer'; export class FileService2 extends Disposable implements IFileService { @@ -39,6 +40,8 @@ export class FileService2 extends Disposable implements IFileService { _serviceBrand: ServiceIdentifier; + private readonly BUFFER_SIZE = 16 * 1024; + constructor(@ILogService private logService: ILogService) { super(); @@ -316,12 +319,12 @@ export class FileService2 extends Disposable implements IFileService { // create file: buffered if (hasOpenReadWriteCloseCapability(provider)) { - await this.doWriteBuffered(provider, resource, new TextEncoder().encode(content)); + await this.doWriteBuffered(provider, resource, VSBuffer.fromString(content || '')); } // create file: unbuffered else if (hasReadWriteCapability(provider)) { - await this.doWriteUnbuffered(provider, resource, new TextEncoder().encode(content), overwrite); + await this.doWriteUnbuffered(provider, resource, VSBuffer.fromString(content || ''), overwrite); } // give up if provider has insufficient capabilities @@ -657,7 +660,7 @@ export class FileService2 extends Disposable implements IFileService { //#region Helpers - private async doWriteBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, buffer: Uint8Array): Promise { + private async doWriteBuffered(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, resource: URI, buffer: VSBuffer): Promise { // open handle const handle = await provider.open(resource, { create: true }); @@ -672,16 +675,16 @@ export class FileService2 extends Disposable implements IFileService { } } - private async doWriteBuffer(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, buffer: Uint8Array, length: number, posInFile: number, posInBuffer: number): Promise { + private async doWriteBuffer(provider: IFileSystemProviderWithOpenReadWriteCloseCapability, handle: number, buffer: VSBuffer, length: number, posInFile: number, posInBuffer: number): Promise { let totalBytesWritten = 0; while (totalBytesWritten < length) { - const bytesWritten = await provider.write(handle, posInFile + totalBytesWritten, buffer, posInBuffer + totalBytesWritten, length - totalBytesWritten); + const bytesWritten = await provider.write(handle, posInFile + totalBytesWritten, buffer.buffer, posInBuffer + totalBytesWritten, length - totalBytesWritten); totalBytesWritten += bytesWritten; } } - private async doWriteUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, buffer: Uint8Array, overwrite: boolean): Promise { - return provider.writeFile(resource, buffer, { create: true, overwrite }); + private async doWriteUnbuffered(provider: IFileSystemProviderWithFileReadWriteCapability, resource: URI, buffer: VSBuffer, overwrite: boolean): Promise { + return provider.writeFile(resource, buffer.buffer, { create: true, overwrite }); } private async doPipeBuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, target: URI): Promise { @@ -694,7 +697,7 @@ export class FileService2 extends Disposable implements IFileService { sourceHandle = await sourceProvider.open(source, { create: false }); targetHandle = await targetProvider.open(target, { create: true }); - const buffer = new Uint8Array(16 * 1024); + const buffer = VSBuffer.alloc(this.BUFFER_SIZE); let posInFile = 0; let posInBuffer = 0; @@ -702,7 +705,7 @@ export class FileService2 extends Disposable implements IFileService { do { // read from source (sourceHandle) at current position (posInFile) into buffer (buffer) at // buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength). - bytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer, posInBuffer, buffer.byteLength - posInBuffer); + bytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer); // write into target (targetHandle) at current position (posInFile) from buffer (buffer) at // buffer position (posInBuffer) all bytes we read (bytesRead). @@ -712,7 +715,7 @@ export class FileService2 extends Disposable implements IFileService { posInBuffer += bytesRead; // when buffer full, fill it again from the beginning - if (posInBuffer === buffer.length) { + if (posInBuffer === buffer.byteLength) { posInBuffer = 0; } } while (bytesRead > 0); @@ -738,7 +741,7 @@ export class FileService2 extends Disposable implements IFileService { // Read entire buffer from source and write buffered try { const buffer = await sourceProvider.readFile(source); - await this.doWriteBuffer(targetProvider, targetHandle, buffer, buffer.byteLength, 0, 0); + await this.doWriteBuffer(targetProvider, targetHandle, VSBuffer.wrap(buffer), buffer.byteLength, 0, 0); } catch (error) { throw error; } finally { @@ -748,27 +751,38 @@ export class FileService2 extends Disposable implements IFileService { private async doPipeBufferedToUnbuffered(sourceProvider: IFileSystemProviderWithOpenReadWriteCloseCapability, source: URI, targetProvider: IFileSystemProviderWithFileReadWriteCapability, target: URI, overwrite: boolean): Promise { - // Determine file size - const size = (await this.resolve(source, { resolveMetadata: true })).size; - // Open handle const sourceHandle = await sourceProvider.open(source, { create: false }); try { - const buffer = new Uint8Array(size); + const buffers: VSBuffer[] = []; - let pos = 0; + let buffer = VSBuffer.alloc(this.BUFFER_SIZE); + + let posInFile = 0; + let totalBytesRead = 0; let bytesRead = 0; + let posInBuffer = 0; do { - // read from source (sourceHandle) at current position (posInFile) into buffer (buffer) at + // read from source (sourceHandle) at current position (pos) into buffer (buffer) at // buffer position (posInBuffer) up to the size of the buffer (buffer.byteLength). - bytesRead = await sourceProvider.read(sourceHandle, pos, buffer, pos, buffer.byteLength - pos); + bytesRead = await sourceProvider.read(sourceHandle, posInFile, buffer.buffer, posInBuffer, buffer.byteLength - posInBuffer); - pos += bytesRead; - } while (bytesRead > 0 && pos < size); + posInFile += bytesRead; + posInBuffer += bytesRead; + totalBytesRead += bytesRead; + + // when buffer full, create a new one + if (posInBuffer === buffer.byteLength) { + buffers.push(buffer); + buffer = VSBuffer.alloc(this.BUFFER_SIZE); + + posInBuffer = 0; + } + } while (bytesRead > 0); // Write buffer into target at once - await this.doWriteUnbuffered(targetProvider, target, buffer, overwrite); + await this.doWriteUnbuffered(targetProvider, target, VSBuffer.concat([...buffers, buffer.slice(0, posInBuffer)], totalBytesRead), overwrite); } catch (error) { throw error; } finally { diff --git a/src/vs/workbench/services/hash/common/hashService.ts b/src/vs/workbench/services/hash/common/hashService.ts index 471a4b14fd3..87fff6a68f6 100644 --- a/src/vs/workbench/services/hash/common/hashService.ts +++ b/src/vs/workbench/services/hash/common/hashService.ts @@ -5,6 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { VSBuffer } from 'vs/base/common/buffer'; export const IHashService = createDecorator('hashService'); @@ -22,7 +23,7 @@ export class HashService implements IHashService { _serviceBrand: any; createSHA1(content: string): Thenable { - return crypto.subtle.digest('SHA-1', new TextEncoder().encode(content)).then(buffer => { + return crypto.subtle.digest('SHA-1', VSBuffer.fromString(content).buffer).then(buffer => { // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string return Array.prototype.map.call(new Uint8Array(buffer), (value: number) => `00${value.toString(16)}`.slice(-2)).join(''); });