Skip to content

Commit 42a1055

Browse files
committed
Add testcase for concurrent transactions
1 parent 95ea37d commit 42a1055

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
import { expect } from "chai";
2+
import { DocumentCollection } from "../collection";
3+
import { Connection } from "../connection";
4+
import { Database } from "../database";
5+
import { Transaction } from "../transaction";
6+
import { config } from "./_config";
7+
8+
const delay = (ms: number) =>
9+
new Promise<void>((resolve) => setTimeout(() => resolve(), ms));
10+
const describe35 = config.arangoVersion! >= 30500 ? describe : describe.skip;
11+
12+
describe35("Transactions", function () {
13+
describe("stream transactions", function () {
14+
this.timeout(0);
15+
let db: Database;
16+
before(async () => {
17+
db = new Database(config);
18+
if (Array.isArray(config.url) && config.loadBalancingStrategy !== "NONE")
19+
await db.acquireHostList();
20+
});
21+
after(() => {
22+
db.close();
23+
});
24+
const name = `testdb_${Date.now()}`;
25+
let collection: DocumentCollection;
26+
let allTransactions: Transaction[];
27+
before(async () => {
28+
allTransactions = [];
29+
await db.createDatabase(name);
30+
db.useDatabase(name);
31+
});
32+
after(async () => {
33+
await Promise.all(
34+
allTransactions.map((transaction) =>
35+
transaction.abort().catch(() => undefined)
36+
)
37+
);
38+
db.useDatabase("_system");
39+
await db.dropDatabase(name);
40+
});
41+
beforeEach(async () => {
42+
collection = await db.createCollection(`collection-${Date.now()}`);
43+
await db.waitForPropagation(
44+
{ path: `/_api/collection/${collection.name}` },
45+
10000
46+
);
47+
});
48+
afterEach(async () => {
49+
try {
50+
await collection.get();
51+
} catch (e) {
52+
return;
53+
}
54+
await collection.drop();
55+
});
56+
57+
it("can run concurrent transactions in parallel", async () => {
58+
const conn = (db as any)._connection as Connection;
59+
const range = Array.from(Array((conn as any)._maxTasks).keys()).map(
60+
(i) => i + 1
61+
);
62+
let failed = 0;
63+
await Promise.all(
64+
range.map(async (i) => {
65+
const started = Date.now();
66+
let trx;
67+
try {
68+
trx = await db.beginTransaction({ exclusive: collection });
69+
console.log(
70+
i,
71+
"trx",
72+
trx.id,
73+
"completed begin after",
74+
Date.now() - started,
75+
"ms elapsed"
76+
);
77+
await trx.step(() => collection.save({ enabled: true }));
78+
console.log(
79+
i,
80+
"trx",
81+
trx.id,
82+
"completed save after",
83+
Date.now() - started,
84+
"ms elapsed"
85+
);
86+
await delay(Math.random() * 10);
87+
await trx.commit();
88+
console.log(
89+
i,
90+
"trx",
91+
trx.id,
92+
"completed commit after",
93+
Date.now() - started,
94+
"ms elapsed"
95+
);
96+
} catch (e) {
97+
console.error(
98+
i,
99+
"trx",
100+
trx ? trx.id : "???",
101+
"failed after",
102+
Date.now() - started,
103+
"ms elapsed:",
104+
String(e)
105+
);
106+
failed++;
107+
}
108+
})
109+
);
110+
expect(failed).to.equal(0);
111+
});
112+
it("respects transactional guarantees", async () => {
113+
const conn = (db as any)._connection as Connection;
114+
const range = Array.from(Array((conn as any)._maxTasks).keys()).map(
115+
(i) => i + 1
116+
);
117+
const key = "test";
118+
await collection.save({ _key: key, i: 0 });
119+
let failed = 0;
120+
await Promise.all(
121+
range.map(async (value) => {
122+
try {
123+
console.log(value, "beginning...");
124+
const trx = await db.beginTransaction({ exclusive: collection });
125+
console.log(value, "begun with ID", trx.id);
126+
const doc = await trx.step(() => collection.document(key));
127+
console.log(value, "waiting...");
128+
await delay(Math.random() * 10);
129+
console.log(
130+
value,
131+
"seen",
132+
doc.i,
133+
"adding",
134+
value,
135+
"=",
136+
doc.i + value
137+
);
138+
await trx.step(() => collection.update(key, { i: doc.i + value }));
139+
console.log(value, "committing");
140+
await trx.commit();
141+
console.log(value, "done");
142+
} catch (e) {
143+
console.error(value, "failed:", String(e));
144+
failed++;
145+
}
146+
})
147+
);
148+
const doc = await collection.document(key);
149+
expect(doc.i).to.equal(range.reduce((a, b) => a + b));
150+
expect(failed).to.equal(0);
151+
});
152+
});
153+
});

0 commit comments

Comments
 (0)