Skip to content

Commit 43ff0b1

Browse files
committed
experiment completed
1 parent 8d9f4a2 commit 43ff0b1

File tree

3 files changed

+100
-13
lines changed

3 files changed

+100
-13
lines changed

packages/firestore/src/api/persistent_cache_index_performance_experiment.ts

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,14 @@ import { AutoId } from '../util/misc';
5252
import { SortedSet } from '../util/sorted_set';
5353

5454
import { Timestamp } from './timestamp';
55+
import { QueryContext } from '../local/query_context';
5556

5657
export async function runPersistentCacheIndexPerformanceExperiment(
57-
log: (...args: unknown[]) => unknown
58+
log: (...args: unknown[]) => unknown,
59+
logLevel: 'info' | 'debug'
5860
): Promise<void> {
5961
const testObjects = await createTestObjects();
60-
const experiment = new AutoIndexingExperiment(log, testObjects);
62+
const experiment = new AutoIndexingExperiment(log, logLevel, testObjects);
6163
await experiment.run();
6264
await testObjects.persistence.shutdown();
6365
}
@@ -73,7 +75,6 @@ interface TestObjects {
7375
}
7476

7577
class AutoIndexingExperiment {
76-
private readonly logFunc: (...args: unknown[]) => unknown;
7778
private readonly persistence: Persistence;
7879
private readonly indexManager: IndexManager;
7980
private readonly remoteDocumentCache: RemoteDocumentCache;
@@ -83,7 +84,8 @@ class AutoIndexingExperiment {
8384
private readonly documentOverlayCache: DocumentOverlayCache;
8485

8586
constructor(
86-
logFunc: (...args: unknown[]) => unknown,
87+
private readonly logFunc: (...args: unknown[]) => unknown,
88+
private readonly logLevel: 'info' | 'debug',
8789
testObjects: TestObjects
8890
) {
8991
this.logFunc = logFunc;
@@ -100,10 +102,10 @@ class AutoIndexingExperiment {
100102
// Every set contains 10 documents
101103
const numOfSet = 100;
102104
// could overflow. Currently it is safe when numOfSet set to 1000 and running on macbook M1
103-
const totalBeforeIndex = 0;
104-
const totalAfterIndex = 0;
105-
const totalDocumentCount = 0;
106-
const totalResultCount = 0;
105+
let totalBeforeIndex = 0;
106+
let totalAfterIndex = 0;
107+
let totalDocumentCount = 0;
108+
let totalResultCount = 0;
107109

108110
// Temperate heuristic, gets when setting numOfSet to 1000.
109111
const withoutIndex = 1;
@@ -117,7 +119,9 @@ class AutoIndexingExperiment {
117119
// portion stands for the percentage of documents matching query
118120
for (let portion = 0; portion <= 10; portion++) {
119121
for (let numOfFields = 1; numOfFields <= 31; numOfFields += 10) {
120-
const basePath = 'documentCount' + totalSetCount;
122+
const basePath =
123+
`${AutoId.newId()}_totalSetCount${totalSetCount}_` +
124+
`portion${portion}_numOfFields${numOfFields}`;
121125
const query = createQuery(basePath, 'match', Operator.EQUAL, true);
122126

123127
// Creates a full matched index for given query.
@@ -135,6 +139,83 @@ class AutoIndexingExperiment {
135139
numOfFields
136140
);
137141
await this.createMutationForCollection(basePath, totalSetCount);
142+
143+
// runs query using full collection scan.
144+
let millisecondsBeforeAuto: number;
145+
let contextWithoutIndexDocumentReadCount: number;
146+
{
147+
const contextWithoutIndex = new QueryContext();
148+
const beforeAutoStart = performance.now();
149+
const beforeAutoResults = await this.persistence.runTransaction(
150+
'executeFullCollectionScan',
151+
'readwrite',
152+
txn =>
153+
this.queryEngine.executeFullCollectionScan(
154+
txn,
155+
query,
156+
contextWithoutIndex
157+
)
158+
);
159+
const beforeAutoEnd = performance.now();
160+
millisecondsBeforeAuto = beforeAutoEnd - beforeAutoStart;
161+
totalBeforeIndex += millisecondsBeforeAuto;
162+
totalDocumentCount += contextWithoutIndex.documentReadCount;
163+
contextWithoutIndexDocumentReadCount =
164+
contextWithoutIndex.documentReadCount;
165+
if (portion * totalSetCount != beforeAutoResults.size) {
166+
throw new Error(
167+
`${
168+
portion * totalSetCount
169+
}!={beforeAutoResults.size} (portion * totalSetCount != beforeAutoResults.size)`
170+
);
171+
}
172+
this.logDebug(
173+
`Running query without using the index took ${millisecondsBeforeAuto}ms`
174+
);
175+
}
176+
177+
// runs query using index look up.
178+
let millisecondsAfterAuto: number;
179+
let autoResultsSize: number;
180+
{
181+
const autoStart = performance.now();
182+
const autoResults = await this.persistence.runTransaction(
183+
'performQueryUsingIndex',
184+
'readwrite',
185+
txn => this.queryEngine.performQueryUsingIndex(txn, query)
186+
);
187+
if (autoResults === null) {
188+
throw new Error('performQueryUsingIndex() returned null');
189+
}
190+
const autoEnd = performance.now();
191+
millisecondsAfterAuto = autoEnd - autoStart;
192+
totalAfterIndex += millisecondsAfterAuto;
193+
if (portion * totalSetCount != autoResults.size) {
194+
throw new Error(
195+
`${
196+
portion * totalSetCount
197+
}!={beforeAutoResults.size} (portion * totalSetCount != beforeAutoResults.size)`
198+
);
199+
}
200+
this.logDebug(
201+
`Running query using the index took ${millisecondsAfterAuto}ms`
202+
);
203+
totalResultCount += autoResults.size;
204+
autoResultsSize = autoResults.size;
205+
}
206+
207+
if (millisecondsBeforeAuto > millisecondsAfterAuto) {
208+
this.log(
209+
`Auto Indexing saves time when total of documents inside ` +
210+
`collection is ${totalSetCount * 10}. ` +
211+
`The matching percentage is ${portion}0%. ` +
212+
`And each document contains ${numOfFields} fields. ` +
213+
`Weight result for without auto indexing is ` +
214+
`${withoutIndex * contextWithoutIndexDocumentReadCount}. ` +
215+
`And weight result for auto indexing is ` +
216+
`${withIndex * autoResultsSize}`
217+
);
218+
}
138219
}
139220
}
140221
}
@@ -146,7 +227,7 @@ class AutoIndexingExperiment {
146227
portion: number /*0 - 10*/,
147228
numOfFields: number /* 1 - 30*/
148229
): Promise<void> {
149-
this.log(
230+
this.logDebug(
150231
`Creating test collection: "${basePath}" ` +
151232
`totalSetCount=${totalSetCount} ` +
152233
`portion=${portion} ` +
@@ -279,6 +360,12 @@ class AutoIndexingExperiment {
279360
);
280361
}
281362

363+
logDebug(...args: unknown[]): void {
364+
if (this.logLevel === 'debug') {
365+
this.logFunc(...args);
366+
}
367+
}
368+
282369
log(...args: unknown[]): void {
283370
this.logFunc(...args);
284371
}

packages/firestore/src/local/query_engine.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ export class QueryEngine {
236236
* Performs an indexed query that evaluates the query based on a collection's
237237
* persisted index values. Returns `null` if an index is not available.
238238
*/
239-
private performQueryUsingIndex(
239+
performQueryUsingIndex(
240240
transaction: PersistenceTransaction,
241241
query: Query
242242
): PersistencePromise<DocumentMap | null> {
@@ -448,7 +448,7 @@ export class QueryEngine {
448448
);
449449
}
450450

451-
private executeFullCollectionScan(
451+
public executeFullCollectionScan(
452452
transaction: PersistenceTransaction,
453453
query: Query,
454454
context: QueryContext

packages/firestore/test/integration/api/temp.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { apiDescribe } from '../util/helpers';
2121
apiDescribe('experiment', persistence => {
2222
it.only('run experiment', function () {
2323
if (persistence.storage === 'indexeddb') {
24-
return runPersistentCacheIndexPerformanceExperiment(console.log);
24+
return runPersistentCacheIndexPerformanceExperiment(console.log, 'info');
2525
} else {
2626
this.skip();
2727
}

0 commit comments

Comments
 (0)