17
17
18
18
import { User } from '../auth/user' ;
19
19
import { DatabaseId } from '../core/database_info' ;
20
+ import { FieldFilter , Operator } from '../core/filter' ;
21
+ import { QueryImpl , queryToTarget } from '../core/query' ;
22
+ import { SnapshotVersion } from '../core/snapshot_version' ;
23
+ import { IndexManager } from '../local/index_manager' ;
20
24
import { IndexedDbIndexManager } from '../local/indexeddb_index_manager' ;
21
25
import { IndexedDbPersistence } from '../local/indexeddb_persistence' ;
22
26
import { LocalDocumentsView } from '../local/local_documents_view' ;
23
27
import { LruParams } from '../local/lru_garbage_collector' ;
28
+ import { Persistence } from '../local/persistence' ;
29
+ import { PersistencePromise } from '../local/persistence_promise' ;
24
30
import { QueryEngine } from '../local/query_engine' ;
31
+ import { documentKeySet , documentMap } from '../model/collections' ;
32
+ import { DocumentKey } from '../model/document_key' ;
33
+ import { IndexOffset } from '../model/field_index' ;
34
+ import { ObjectValue } from '../model/object_value' ;
35
+ import { FieldPath , ResourcePath } from '../model/path' ;
25
36
import { getDocument , getWindow } from '../platform/dom' ;
26
37
import { JsonProtoSerializer } from '../remote/serializer' ;
27
38
import { AsyncQueueImpl } from '../util/async_queue_impl' ;
28
39
import { AutoId } from '../util/misc' ;
29
40
30
- export function runPersistentCacheIndexPerformanceExperiment (
41
+ import { Timestamp } from './timestamp' ;
42
+
43
+
44
+ interface ExperimentConfig {
45
+ /** The number of documents to create in the collection. */
46
+ documentCount : number ;
47
+ /** The number of fields in each document. */
48
+ fieldCount : number ;
49
+ /** The number of documents that match the query. */
50
+ documentMatchCount : number ;
51
+ }
52
+
53
+ export async function runPersistentCacheIndexPerformanceExperiment (
54
+ config : ExperimentConfig ,
31
55
log : ( ...args : unknown [ ] ) => unknown
32
- ) : void {
33
- const { queryEngine } = createTestObjects ( ) ;
34
- log ( 'Created QueryEngine' , queryEngine ) ;
56
+ ) : Promise < void > {
57
+ const { persistence, indexManager, queryEngine } = await createTestObjects ( ) ;
58
+ const collectionId = AutoId . newId ( ) ;
59
+
60
+ const query = createQuery ( collectionId , 'matches' , Operator . EQUAL , true ) ;
61
+ const target = queryToTarget ( query ) ;
62
+ await persistence . runTransaction ( 'createTargetIndexes' , 'readwrite' , txn => {
63
+ log ( 'createTargetIndexes()' ) ;
64
+ return indexManager . createTargetIndexes ( txn , queryToTarget ( query ) ) ;
65
+ } ) ;
66
+
67
+ await persistence . runTransaction ( 'populate collection' , 'readwrite' , txn => {
68
+ log ( 'populate collection' ) ;
69
+ const documentIds : string [ ] = [ ] ;
70
+ for ( let i = 0 ; i < config . documentCount ; i ++ ) {
71
+ documentIds . push ( AutoId . newId ( ) ) ;
72
+ }
73
+ const matchingDocumentIds = new Set < string > ( ) ;
74
+ while ( matchingDocumentIds . size < config . documentMatchCount ) {
75
+ const matchingDocumentIdIndex = Math . floor (
76
+ Math . random ( ) * documentIds . length
77
+ ) ;
78
+ matchingDocumentIds . add ( documentIds [ matchingDocumentIdIndex ] ) ;
79
+ }
80
+ const documents : Array < { documentId : string ; value : ObjectValue } > = [ ] ;
81
+ for ( const documentId of documentIds ) {
82
+ const value = ObjectValue . empty ( ) ;
83
+ for ( let fieldIndex = 0 ; fieldIndex < config . fieldCount ; fieldIndex ++ ) {
84
+ const fieldPath = new FieldPath ( [ AutoId . newId ( ) ] ) ;
85
+ value . set ( fieldPath , { stringValue : `field${ fieldIndex } ` } ) ;
86
+ }
87
+ if ( matchingDocumentIds . has ( documentId ) ) {
88
+ value . set ( new FieldPath ( [ 'matches' ] ) , { booleanValue : true } ) ;
89
+ }
90
+ documents . push ( { documentId, value } ) ;
91
+ }
92
+ return PersistencePromise . forEach (
93
+ documents ,
94
+ ( documentInfo : { documentId : string ; value : ObjectValue } ) => {
95
+ const { documentId, value } = documentInfo ;
96
+ const documentKey = DocumentKey . fromSegments ( [
97
+ collectionId ,
98
+ documentId
99
+ ] ) ;
100
+ const changeBuffer = persistence
101
+ . getRemoteDocumentCache ( )
102
+ . newChangeBuffer ( ) ;
103
+ return changeBuffer . getEntry ( txn , documentKey ) . next ( document => {
104
+ changeBuffer . addEntry (
105
+ document . convertToFoundDocument (
106
+ SnapshotVersion . fromTimestamp ( Timestamp . fromMillis ( 1 ) ) ,
107
+ value
108
+ )
109
+ ) ;
110
+ return changeBuffer
111
+ . apply ( txn )
112
+ . next ( ( ) =>
113
+ indexManager . updateIndexEntries ( txn , documentMap ( document ) )
114
+ )
115
+ . next ( ( ) =>
116
+ indexManager . updateCollectionGroup (
117
+ txn ,
118
+ collectionId ,
119
+ new IndexOffset ( document . readTime , document . key , - 1 )
120
+ )
121
+ ) ;
122
+ } ) ;
123
+ }
124
+ ) ;
125
+ } ) ;
126
+
127
+ const queryResult = await persistence . runTransaction (
128
+ 'populate collection' ,
129
+ 'readwrite' ,
130
+ txn => {
131
+ log ( 'getDocumentsMatchingQuery()' ) ;
132
+ return queryEngine . getDocumentsMatchingQuery (
133
+ txn ,
134
+ query ,
135
+ SnapshotVersion . min ( ) ,
136
+ documentKeySet ( )
137
+ ) ;
138
+ }
139
+ ) ;
140
+
141
+ log ( `getDocumentsMatchingQuery() returned ${ queryResult . size } documents` ) ;
142
+
143
+ await persistence . shutdown ( ) ;
35
144
}
36
145
37
146
interface TestObjects {
147
+ persistence : Persistence ;
148
+ indexManager : IndexManager ;
38
149
queryEngine : QueryEngine ;
39
150
}
40
151
41
- function createTestObjects ( ) : TestObjects {
152
+ async function createTestObjects ( ) : Promise < TestObjects > {
42
153
const databaseId = new DatabaseId ( /*projectId=*/ AutoId . newId ( ) ) ;
43
154
const user = new User ( /*uid=*/ null ) ;
44
155
const persistence = new IndexedDbPersistence (
@@ -60,6 +171,8 @@ function createTestObjects(): TestObjects {
60
171
/*forceOwningTab=*/ false
61
172
) ;
62
173
174
+ await persistence . start ( ) ;
175
+
63
176
const remoteDocumentCache = persistence . getRemoteDocumentCache ( ) ;
64
177
const indexManager = new IndexedDbIndexManager ( user , databaseId ) ;
65
178
const mutationQueue = persistence . getMutationQueue ( user , indexManager ) ;
@@ -73,5 +186,21 @@ function createTestObjects(): TestObjects {
73
186
const queryEngine = new QueryEngine ( ) ;
74
187
queryEngine . initialize ( localDocumentView , indexManager ) ;
75
188
76
- return { queryEngine } ;
189
+ return { persistence, indexManager, queryEngine } ;
190
+ }
191
+
192
+ function createQuery (
193
+ path : string ,
194
+ field : string ,
195
+ op : Operator ,
196
+ value : boolean
197
+ ) : QueryImpl {
198
+ const fieldPath = FieldPath . fromServerFormat ( field ) ;
199
+ const filter = FieldFilter . create ( fieldPath , op , { booleanValue : value } ) ;
200
+ return new QueryImpl (
201
+ /*path=*/ ResourcePath . fromString ( path ) ,
202
+ /*collectionGroup=*/ null ,
203
+ /*explicitOrderBy=*/ [ ] ,
204
+ /*filters=*/ [ filter ]
205
+ ) ;
77
206
}
0 commit comments