Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
},
"dependencies": {
"@mongodb-js/saslprep": "^1.1.9",
"bson": "^6.10.0",
"bson": "^6.10.1",
"mongodb-connection-string-url": "^3.0.0"
},
"peerDependencies": {
Expand Down
67 changes: 33 additions & 34 deletions src/cmap/connect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,15 +386,35 @@ export async function makeSocket(options: MakeConnectionOptions): Promise<Stream
if (existingSocket) {
resolve(socket);
} else {
const start = performance.now();
const connectEvent = useTLS ? 'secureConnect' : 'connect';
socket
.once(connectEvent, () => resolve(socket))
.once('error', error => reject(connectionFailureError('error', error)))
.once('timeout', () => reject(connectionFailureError('timeout')))
.once('close', () => reject(connectionFailureError('close')));
.once('error', cause =>
reject(new MongoNetworkError(MongoError.buildErrorMessage(cause), { cause }))
)
.once('timeout', () => {
reject(
new MongoNetworkTimeoutError(
`Socket '${connectEvent}' timed out after ${(performance.now() - start) | 0}ms (connectTimeoutMS: ${connectTimeoutMS})`
)
);
})
.once('close', () =>
reject(
new MongoNetworkError(
`Socket closed after ${(performance.now() - start) | 0} during connection establishment`
)
)
);

if (options.cancellationToken != null) {
cancellationHandler = () => reject(connectionFailureError('cancel'));
cancellationHandler = () =>
reject(
new MongoNetworkError(
`Socket connection establishment was cancelled after ${(performance.now() - start) | 0}`
)
);
options.cancellationToken.once('cancel', cancellationHandler);
}
}
Expand Down Expand Up @@ -447,9 +467,11 @@ async function makeSocks5Connection(options: MakeConnectionOptions): Promise<Str

socks ??= loadSocks();

let existingSocket: Stream;

try {
// Then, establish the Socks5 proxy connection:
const { socket } = await socks.SocksClient.createConnection({
const connection = await socks.SocksClient.createConnection({
existing_socket: rawSocket,
timeout: options.connectTimeoutMS,
command: 'connect',
Expand All @@ -466,35 +488,12 @@ async function makeSocks5Connection(options: MakeConnectionOptions): Promise<Str
password: options.proxyPassword || undefined
}
});

// Finally, now treat the resulting duplex stream as the
// socket over which we send and receive wire protocol messages:
return await makeSocket({
...options,
existingSocket: socket,
proxyHost: undefined
});
} catch (error) {
throw connectionFailureError('error', error);
existingSocket = connection.socket;
} catch (cause) {
throw new MongoNetworkError(MongoError.buildErrorMessage(cause), { cause });
}
}

function connectionFailureError(type: 'error', cause: Error): MongoNetworkError;
function connectionFailureError(type: 'close' | 'timeout' | 'cancel'): MongoNetworkError;
function connectionFailureError(
type: 'error' | 'close' | 'timeout' | 'cancel',
cause?: Error
): MongoNetworkError {
switch (type) {
case 'error':
return new MongoNetworkError(MongoError.buildErrorMessage(cause), { cause });
case 'timeout':
return new MongoNetworkTimeoutError('connection timed out');
case 'close':
return new MongoNetworkError('connection closed');
case 'cancel':
return new MongoNetworkError('connection establishment was cancelled');
default:
return new MongoNetworkError('unknown network error');
}
// Finally, now treat the resulting duplex stream as the
// socket over which we send and receive wire protocol messages:
return await makeSocket({ ...options, existingSocket, proxyHost: undefined });
}
78 changes: 73 additions & 5 deletions test/benchmarks/driverBench/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,72 @@ const fs = require('fs');
const path = require('path');
const { Readable } = require('stream');
const { pipeline } = require('stream/promises');
const { MongoClient } = require('../../..');
const { GridFSBucket } = require('../../..');
// eslint-disable-next-line no-restricted-modules
const { MONGODB_ERROR_CODES } = require('../../../lib/error');
const child_process = require('child_process');

/**
* The path to the MongoDB Node.js driver.
* This MUST be set to the directory the driver is installed in
* NOT the file "lib/index.js" that is the driver's export.
*/
const MONGODB_DRIVER_PATH = (() => {
let driverPath = process.env.MONGODB_DRIVER_PATH;
if (!driverPath?.length) {
driverPath = path.resolve(__dirname, '../../..');
}
return driverPath;
})();

const { MongoClient, GridFSBucket } = require(MONGODB_DRIVER_PATH);

/** Grab the version from the package.json */
const { version: MONGODB_DRIVER_VERSION } = require(path.join(MONGODB_DRIVER_PATH, 'package.json'));

/**
* Use git to optionally determine the git revision,
* but the benchmarks could be run against an npm installed version so this should be allowed to fail
*/
const MONGODB_DRIVER_REVISION = (() => {
try {
return child_process
.execSync('git rev-parse --short HEAD', {
cwd: MONGODB_DRIVER_PATH,
encoding: 'utf8'
})
.trim();
} catch {
return 'unknown revision';
}
})();

/**
* Find the BSON dependency inside the driver PATH given and grab the version from the package.json.
*/
const MONGODB_BSON_PATH = path.join(MONGODB_DRIVER_PATH, 'node_modules', 'bson');
const { version: MONGODB_BSON_VERSION } = require(path.join(MONGODB_BSON_PATH, 'package.json'));

/**
* If you need to test BSON changes, you should clone, checkout and build BSON.
* run: `npm link` with no arguments to register the link.
* Then in the driver you are testing run `npm link bson` to use your local build.
*
* This will symlink the BSON into the driver's node_modules directory. So here
* we can find the revision of the BSON we are testing against if .git exists.
*/
const MONGODB_BSON_REVISION = (() => {
if (!fs.existsSync(path.join(MONGODB_BSON_PATH, '.git'))) {
return 'installed from npm';
}
try {
return child_process
.execSync('git rev-parse --short HEAD', {
cwd: path.join(MONGODB_BSON_PATH),
encoding: 'utf8'
})
.trim();
} catch {
return 'unknown revision';
}
})();

const DB_NAME = 'perftest';
const COLLECTION_NAME = 'corpus';
Expand Down Expand Up @@ -67,7 +129,7 @@ function initCollection() {

function dropCollection() {
return this.collection.drop().catch(e => {
if (e.code !== MONGODB_ERROR_CODES.NamespaceNotFound) {
if (e.code !== 26 /* NamespaceNotFound */) {
throw e;
}
});
Expand Down Expand Up @@ -117,6 +179,12 @@ async function writeSingleByteFileToBucket() {
module.exports = {
MONGODB_URI,
MONGODB_CLIENT_OPTIONS,
MONGODB_DRIVER_PATH,
MONGODB_DRIVER_VERSION,
MONGODB_DRIVER_REVISION,
MONGODB_BSON_PATH,
MONGODB_BSON_VERSION,
MONGODB_BSON_REVISION,
makeClient,
connectClient,
disconnectClient,
Expand Down
8 changes: 4 additions & 4 deletions test/benchmarks/driverBench/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ benchmarkRunner
// https://spruce.mongodb.com/task/mongo_node_driver_next_performance_tests_run_spec_benchmark_tests_node_server_4bc3e500b6f0e8ab01f052c4a1bfb782d6a29b4e_f168e1328f821bbda265e024cc91ae54_24_11_18_15_37_24/logs?execution=0

const parallelBench = average([
microBench.parallel.ldjsonMultiFileUpload ?? 44.02343490518617,
microBench.parallel.ldjsonMultiFileExport ?? 31.83182984813926,
microBench.parallel.ldjsonMultiFileUpload,
microBench.parallel.ldjsonMultiFileExport,
microBench.parallel.gridfsMultiFileUpload,
microBench.parallel.gridfsMultiFileDownload
]);
Expand All @@ -63,15 +63,15 @@ benchmarkRunner
microBench.multiBench.findManyAndEmptyCursor,
microBench.multiBench.gridFsDownload,
microBench.parallel.gridfsMultiFileDownload,
microBench.parallel.ldjsonMultiFileExport ?? 31.83182984813926
microBench.parallel.ldjsonMultiFileExport
]);
const writeBench = average([
microBench.singleBench.smallDocInsertOne,
microBench.singleBench.largeDocInsertOne,
microBench.multiBench.smallDocBulkInsert,
microBench.multiBench.largeDocBulkInsert,
microBench.multiBench.gridFsUpload,
microBench.parallel.ldjsonMultiFileUpload ?? 44.02343490518617,
microBench.parallel.ldjsonMultiFileUpload,
microBench.parallel.gridfsMultiFileUpload
]);

Expand Down
78 changes: 39 additions & 39 deletions test/benchmarks/mongoBench/suites/parallelBench.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ const {
dropBucket,
initCollection,
initDb,
connectClient
connectClient,
dropCollection,
createCollection
} = require('../../driverBench/common');
const { pipeline } = require('stream/promises');
const { EJSON } = require('bson');
Expand All @@ -34,7 +36,6 @@ async function clearTemporaryDirectory() {
await Promise.all(files.map(file => rm(file)));
}

// eslint-disable-next-line no-unused-vars
async function ldjsonMultiUpload() {
const directory = resolve(benchmarkFileDirectory, 'ldjson_multi');
const files = await readdir(directory);
Expand Down Expand Up @@ -63,7 +64,6 @@ async function ldjsonMultiUpload() {
await Promise.all(uploads);
}

// eslint-disable-next-line no-unused-vars
async function ldjsonMultiExport() {
const skips = Array.from({ length: 100 }, (_, index) => index * 5000);

Expand Down Expand Up @@ -113,43 +113,43 @@ async function gridfsMultiFileDownload() {
* @returns Benchmark
*/
function makeParallelBenchmarks(suite) {
// .benchmark('ldjsonMultiFileUpload', benchmark =>
// // https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst#ldjson-multi-file-import
// benchmark
// .taskSize(565)
// .setup(makeClient)
// .setup(connectClient)
// .setup(initDb)
// .setup(dropDb)
// .beforeTask(initCollection)
// .beforeTask(dropCollection)
// .beforeTask(createCollection)
// .task(ldjsonMultiUpload)
// .teardown(dropDb)
// .teardown(disconnectClient)
// )
// .benchmark('ldjsonMultiFileExport', benchmark =>
// // https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst#ldjson-multi-file-export
// benchmark
// .taskSize(565)
// .setup(makeClient)
// .setup(connectClient)
// .setup(initDb)
// .setup(dropDb)
// .beforeTask(initCollection)
// .beforeTask(dropCollection)
// .beforeTask(createCollection)
// .beforeTask(ldjsonMultiUpload)
// .beforeTask(initTemporaryDirectory)
// .task(ldjsonMultiExport)
// .afterTask(clearTemporaryDirectory)
// .teardown(dropDb)
// .teardown(async function () {
// await rm(this.temporaryDirectory, { recursive: true, force: true });
// })
// .teardown(disconnectClient)
// )
return suite
.benchmark('ldjsonMultiFileUpload', benchmark =>
// https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst#ldjson-multi-file-import
benchmark
.taskSize(565)
.setup(makeClient)
.setup(connectClient)
.setup(initDb)
.setup(dropDb)
.beforeTask(initCollection)
.beforeTask(dropCollection)
.beforeTask(createCollection)
.task(ldjsonMultiUpload)
.teardown(dropDb)
.teardown(disconnectClient)
)
.benchmark('ldjsonMultiFileExport', benchmark =>
// https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst#ldjson-multi-file-export
benchmark
.taskSize(565)
.setup(makeClient)
.setup(connectClient)
.setup(initDb)
.setup(dropDb)
.beforeTask(initCollection)
.beforeTask(dropCollection)
.beforeTask(createCollection)
.beforeTask(ldjsonMultiUpload)
.beforeTask(initTemporaryDirectory)
.task(ldjsonMultiExport)
.afterTask(clearTemporaryDirectory)
.teardown(dropDb)
.teardown(async function () {
await rm(this.temporaryDirectory, { recursive: true, force: true });
})
.teardown(disconnectClient)
)
.benchmark('gridfsMultiFileUpload', benchmark =>
// https://github.com/mongodb/specifications/blob/master/source/benchmarking/benchmarking.rst#gridfs-multi-file-upload
benchmark
Expand Down
Loading