Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
…PASS-8441-global0=-writes-tests
  • Loading branch information
mabaasit committed Nov 4, 2024
2 parents 994044d + 6c4d534 commit 86c73ee
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 8 deletions.
2 changes: 1 addition & 1 deletion THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
The following third-party software is used by and included in **Mongodb Compass**.
This document was automatically generated on Fri Nov 01 2024.
This document was automatically generated on Mon Nov 04 2024.

## List of dependencies

Expand Down
2 changes: 1 addition & 1 deletion docs/tracking-plan.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Compass Tracking Plan

Generated on Fri, Nov 1, 2024 at 01:56 PM
Generated on Mon, Nov 4, 2024 at 01:16 PM

## Table of Contents

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { Compass } from '../../helpers/compass';
import { cleanup, init, Selectors } from '../../helpers/compass';
import {
cleanup,
init,
screenshotIfFailed,
Selectors,
} from '../../helpers/compass';
import type { CompassBrowser } from '../../helpers/compass-browser';
import { createNumbersCollection } from '../../helpers/insert-data';
import {
Expand All @@ -11,16 +16,20 @@ describe('Rolling indexes', function () {
let compass: Compass;
let browser: CompassBrowser;

before(async function () {
before(function () {
if (!isTestingAtlasCloudSandbox()) {
this.skip();
}
});

beforeEach(async function () {
compass = await init(this.test?.fullTitle());
browser = compass.browser;
await browser.setupDefaultConnections();
});

before(function () {
if (!isTestingAtlasCloudSandbox()) {
this.skip();
}
afterEach(async function () {
await screenshotIfFailed(compass, this.currentTest);
});

after(async function () {
Expand Down
28 changes: 28 additions & 0 deletions packages/compass-user-data/src/semaphore.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { expect } from 'chai';
import { Semaphore } from './semaphore';

describe('semaphore', function () {
const maxConcurrentOps = 5;
let semaphore: Semaphore;
let taskHandler: (id: number) => Promise<number>;

beforeEach(() => {
semaphore = new Semaphore(maxConcurrentOps);
taskHandler = async (id: number) => {
const release = await semaphore.waitForRelease();
const delay = Math.floor(Math.random() * 450) + 50;
try {
await new Promise((resolve) => setTimeout(resolve, delay));
return id;
} finally {
release();
}
};
});

it('should run operations concurrently', async function () {
const tasks = Array.from({ length: 10 }, (_, i) => taskHandler(i));
const results = await Promise.all(tasks);
expect(results).to.have.lengthOf(10);
});
});
27 changes: 27 additions & 0 deletions packages/compass-user-data/src/semaphore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export class Semaphore {
private currentCount = 0;
private queue: (() => void)[] = [];
constructor(private maxConcurrentOps: number) {}

waitForRelease(): Promise<() => void> {
return new Promise((resolve) => {
const attempt = () => {
this.currentCount++;
resolve(this.release.bind(this));
};
if (this.currentCount < this.maxConcurrentOps) {
attempt();
} else {
this.queue.push(attempt);
}
});
}

private release() {
this.currentCount--;
if (this.queue.length > 0) {
const next = this.queue.shift();
next && next();
}
}
}
5 changes: 5 additions & 0 deletions packages/compass-user-data/src/user-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { createLogger } from '@mongodb-js/compass-logging';
import { getStoragePath } from '@mongodb-js/compass-utils';
import type { z } from 'zod';
import writeFile from 'write-file-atomic';
import { Semaphore } from './semaphore';

const { log, mongoLogId } = createLogger('COMPASS-USER-STORAGE');

Expand Down Expand Up @@ -68,6 +69,7 @@ export class UserData<T extends z.Schema> {
private readonly serialize: SerializeContent<z.input<T>>;
private readonly deserialize: DeserializeContent;
private readonly getFileName: GetFileName;
private readonly semaphore = new Semaphore(100);

constructor(
private readonly validator: T,
Expand Down Expand Up @@ -122,7 +124,9 @@ export class UserData<T extends z.Schema> {
let data: string;
let stats: Stats;
let handle: fs.FileHandle | undefined = undefined;
let release: (() => void) | undefined = undefined;
try {
release = await this.semaphore.waitForRelease();
handle = await fs.open(absolutePath, 'r');
[stats, data] = await Promise.all([
handle.stat(),
Expand All @@ -139,6 +143,7 @@ export class UserData<T extends z.Schema> {
throw error;
} finally {
await handle?.close();
release?.();
}

try {
Expand Down

0 comments on commit 86c73ee

Please sign in to comment.