@itwin/core-backend
Version:
iTwin.js backend components
164 lines • 7.53 kB
JavaScript
import { DbResponseStatus } from "@itwin/core-common";
import { expect } from "chai";
import { ConcurrentQuery } from "../../ConcurrentQuery";
import { SnapshotDb } from "../../IModelDb";
import { _nativeDb } from "../../core-backend";
import { IModelTestUtils } from "../IModelTestUtils";
async function delay(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
describe("ConcurrentQuery", () => {
it("default config", () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
const defaultConfig = {
autoShutdownWhenIdleForSeconds: 1800,
doNotUsePrimaryConnToPrepare: false,
globalQuota: { time: 60, memory: 8388608 },
ignoreDelay: true,
ignorePriority: false,
memoryMapFileSize: 0,
monitorPollInterval: 5000,
progressOpCount: 5000,
requestQueueSize: 2000,
statementCacheSizePerWorker: 40,
workerThreads: 4,
};
const config = ConcurrentQuery.resetConfig(db[_nativeDb], {});
expect(config).deep.eq(defaultConfig);
db.close();
});
it("modify config", () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
const modifiedConfig = {
autoShutdownWhenIdleForSeconds: 100,
doNotUsePrimaryConnToPrepare: true,
globalQuota: { time: 10, memory: 1000000 },
ignoreDelay: false,
ignorePriority: true,
memoryMapFileSize: 100,
monitorPollInterval: 2000,
progressOpCount: 6000,
requestQueueSize: 1000,
statementCacheSizePerWorker: 20,
workerThreads: 3,
};
const config = ConcurrentQuery.resetConfig(db[_nativeDb], modifiedConfig);
expect(config).deep.eq(modifiedConfig);
db.close();
});
it("time limit check", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 1, memory: 100000 }, progressOpCount: 1000 });
// await runSingleRequest(db, `SELECT 1`);
const req = {
query: `WITH sequence(n,k) AS (
SELECT 1,1 UNION ALL SELECT n + 1, random() FROM sequence WHERE n < 10000000
) SELECT COUNT(*) FROM sequence s`
};
const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
expect(resp.status).equals(DbResponseStatus.Partial);
expect(resp.stats.timeLimit).equals(1000);
expect(resp.stats.memLimit).equals(100000);
expect(resp.stats.cpuTime).to.be.closeTo(1000970, 500000);
expect(resp.stats.totalTime).to.be.closeTo(1001, 100);
expect(resp.stats.memUsed).to.be.closeTo(2, 3);
expect(resp.stats.prepareTime).to.be.closeTo(0, 2);
db.close();
});
it("memory limit check", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 1000 }, progressOpCount: 1000 });
// await runSingleRequest(db, `SELECT 1`);
const req = {
query: `WITH sequence(n) AS (
SELECT 1
UNION ALL
SELECT n + 1 FROM sequence WHERE n < 10000000
)
SELECT 'xxxxxxxxxx-xxxxxxxxxx-xxxxxxxxxx' FROM sequence s`
};
const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
expect(resp.status).equals(DbResponseStatus.Partial);
expect(resp.stats.timeLimit).equals(60000);
expect(resp.stats.memLimit).equals(1000);
expect(resp.stats.memUsed).to.be.closeTo(1037, 100);
db.close();
});
it("prepare error", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
const req = {
query: `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`
};
const resp = await ConcurrentQuery.executeQueryRequest(db[_nativeDb], req);
expect(resp.status).equals(DbResponseStatus.Error_ECSql_PreparedFailed);
db.close();
});
it("restart query", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
ConcurrentQuery.resetConfig(db[_nativeDb], { globalQuota: { time: 60, memory: 10000000 }, progressOpCount: 1000 });
const req0 = {
query: `WITH sequence(n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
) SELECT n FROM sequence s`,
restartToken: "Blah",
};
const req1 = {
query: `WITH sequence(n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 1000
) SELECT n FROM sequence s`,
restartToken: "Blah",
};
const resp1 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req0);
await delay(1);
const resp2 = ConcurrentQuery.executeQueryRequest(db[_nativeDb], req1);
const resp = await Promise.all([resp1, resp2]);
expect(resp[0].status).equals(DbResponseStatus.Cancel);
expect(resp[1].status).equals(DbResponseStatus.Done);
db.close();
});
it("queue limit check", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
ConcurrentQuery.resetConfig(db[_nativeDb], { requestQueueSize: 40, globalQuota: { time: 5, memory: 100000 } });
const req = {
query: `WITH sequence(n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
) SELECT n FROM sequence s`,
};
const responsePromises = [];
for (let i = 0; i < 60; ++i) {
responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
}
const responses = await Promise.all(responsePromises);
const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.QueueFull));
expect(queueResponses.length).to.be.greaterThanOrEqual(10);
db.close();
});
it("timeout check", async () => {
const testFile = IModelTestUtils.resolveAssetFile("test.bim");
const db = SnapshotDb.openFile(testFile);
ConcurrentQuery.resetConfig(db[_nativeDb], { monitorPollInterval: 1, globalQuota: { time: 5, memory: 10000000 } });
const req = {
query: `WITH sequence(n) AS (
SELECT 1 UNION ALL SELECT n + 1 FROM sequence WHERE n < 10000000
) SELECT n FROM sequence s`,
};
const responsePromises = [];
for (let i = 0; i < 100; ++i) {
responsePromises.push(ConcurrentQuery.executeQueryRequest(db[_nativeDb], req));
}
const responses = await Promise.all(responsePromises);
const queueResponses = Array.from(responses.filter((x) => x.status === DbResponseStatus.Timeout));
expect(queueResponses.length).to.be.greaterThanOrEqual(10);
db.close();
});
});
//# sourceMappingURL=ConcurrentQuery.test.js.map