1 /*
2  * Copyright 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.appsearch.external.localstorage.stats;
18 
19 import android.annotation.IntDef;
20 import android.annotation.NonNull;
21 import android.app.appsearch.AppSearchResult;
22 import android.app.appsearch.annotation.CanIgnoreReturnValue;
23 
24 import java.lang.annotation.Retention;
25 import java.lang.annotation.RetentionPolicy;
26 import java.util.Objects;
27 
28 /**
29  * Class holds detailed stats for initialization
30  *
31  * @hide
32  */
33 public final class InitializeStats {
34     /**
35      * The cause of IcingSearchEngine recovering from a previous bad state during initialization.
36      */
37     @IntDef(
38             value = {
39                 // It needs to be sync with RecoveryCause in
40                 // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto
41                 RECOVERY_CAUSE_NONE,
42                 RECOVERY_CAUSE_DATA_LOSS,
43                 RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH,
44                 RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH,
45                 RECOVERY_CAUSE_IO_ERROR,
46             })
47     @Retention(RetentionPolicy.SOURCE)
48     public @interface RecoveryCause {}
49 
50     // No recovery happened.
51     public static final int RECOVERY_CAUSE_NONE = 0;
52     // Data loss in ground truth.
53     public static final int RECOVERY_CAUSE_DATA_LOSS = 1;
54     // Data in index is inconsistent with ground truth.
55     public static final int RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH = 2;
56     // Total checksum of all the components does not match.
57     public static final int RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH = 3;
58     // Random I/O errors.
59     public static final int RECOVERY_CAUSE_IO_ERROR = 4;
60 
61     /** Status regarding how much data is lost during the initialization. */
62     @IntDef(
63             value = {
64                 // It needs to be sync with DocumentStoreDataStatus in
65                 // external/icing/proto/icing/proto/logging.proto#InitializeStatsProto
66 
67                 DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS,
68                 DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS,
69                 DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS,
70             })
71     @Retention(RetentionPolicy.SOURCE)
72     public @interface DocumentStoreDataStatus {}
73 
74     // Document store is successfully initialized or fully recovered.
75     public static final int DOCUMENT_STORE_DATA_STATUS_NO_DATA_LOSS = 0;
76     // Ground truth data is partially lost.
77     public static final int DOCUMENT_STORE_DATA_STATUS_PARTIAL_LOSS = 1;
78     // Ground truth data is completely lost.
79     public static final int DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS = 2;
80 
81     @AppSearchResult.ResultCode private final int mStatusCode;
82     private final int mTotalLatencyMillis;
83 
84     /** Whether the initialize() detects deSync. */
85     private final boolean mHasDeSync;
86 
87     /** Time used to read and process the schema and namespaces. */
88     private final int mPrepareSchemaAndNamespacesLatencyMillis;
89 
90     /** Time used to read and process the visibility store. */
91     private final int mPrepareVisibilityStoreLatencyMillis;
92 
93     /** Overall time used for the native function call. */
94     private final int mNativeLatencyMillis;
95 
96     @RecoveryCause private final int mNativeDocumentStoreRecoveryCause;
97     @RecoveryCause private final int mNativeIndexRestorationCause;
98     @RecoveryCause private final int mNativeSchemaStoreRecoveryCause;
99 
100     /** Time used to recover the document store. */
101     private final int mNativeDocumentStoreRecoveryLatencyMillis;
102 
103     /** Time used to restore the index. */
104     private final int mNativeIndexRestorationLatencyMillis;
105 
106     /** Time used to recover the schema store. */
107     private final int mNativeSchemaStoreRecoveryLatencyMillis;
108 
109     /** Status regarding how much data is lost during the initialization. */
110     private final int mNativeDocumentStoreDataStatus;
111 
112     /**
113      * Returns number of documents currently in document store. Those may include alive, deleted,
114      * and expired documents.
115      */
116     private final int mNativeNumDocuments;
117 
118     /** Returns number of schema types currently in the schema store. */
119     private final int mNativeNumSchemaTypes;
120 
121     /** Whether we had to reset the index, losing all data, during initialization. */
122     private final boolean mHasReset;
123 
124     /** If we had to reset, contains the status code of the reset operation. */
125     @AppSearchResult.ResultCode private final int mResetStatusCode;
126 
127     /** Returns the status of the initialization. */
128     @AppSearchResult.ResultCode
getStatusCode()129     public int getStatusCode() {
130         return mStatusCode;
131     }
132 
133     /** Returns the total latency in milliseconds for the initialization. */
getTotalLatencyMillis()134     public int getTotalLatencyMillis() {
135         return mTotalLatencyMillis;
136     }
137 
138     /**
139      * Returns whether the initialize() detects deSync.
140      *
141      * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent view
142      * of what data should exist.
143      */
hasDeSync()144     public boolean hasDeSync() {
145         return mHasDeSync;
146     }
147 
148     /** Returns time used to read and process the schema and namespaces. */
getPrepareSchemaAndNamespacesLatencyMillis()149     public int getPrepareSchemaAndNamespacesLatencyMillis() {
150         return mPrepareSchemaAndNamespacesLatencyMillis;
151     }
152 
153     /** Returns time used to read and process the visibility file. */
getPrepareVisibilityStoreLatencyMillis()154     public int getPrepareVisibilityStoreLatencyMillis() {
155         return mPrepareVisibilityStoreLatencyMillis;
156     }
157 
158     /** Returns overall time used for the native function call. */
getNativeLatencyMillis()159     public int getNativeLatencyMillis() {
160         return mNativeLatencyMillis;
161     }
162 
163     /**
164      * Returns recovery cause for document store.
165      *
166      * <p>Possible recovery causes for document store:
167      * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS}
168      * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
169      * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
170      */
171     @RecoveryCause
getDocumentStoreRecoveryCause()172     public int getDocumentStoreRecoveryCause() {
173         return mNativeDocumentStoreRecoveryCause;
174     }
175 
176     /**
177      * Returns restoration cause for index store.
178      *
179      * <p>Possible causes:
180      * <li>{@link InitializeStats#RECOVERY_CAUSE_INCONSISTENT_WITH_GROUND_TRUTH}
181      * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
182      * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
183      */
184     @RecoveryCause
getIndexRestorationCause()185     public int getIndexRestorationCause() {
186         return mNativeIndexRestorationCause;
187     }
188 
189     /**
190      * Returns recovery cause for schema store.
191      *
192      * <p>Possible causes:
193      * <li>IO_ERROR
194      */
195     @RecoveryCause
getSchemaStoreRecoveryCause()196     public int getSchemaStoreRecoveryCause() {
197         return mNativeSchemaStoreRecoveryCause;
198     }
199 
200     /** Returns time used to recover the document store. */
getDocumentStoreRecoveryLatencyMillis()201     public int getDocumentStoreRecoveryLatencyMillis() {
202         return mNativeDocumentStoreRecoveryLatencyMillis;
203     }
204 
205     /** Returns time used to restore the index. */
getIndexRestorationLatencyMillis()206     public int getIndexRestorationLatencyMillis() {
207         return mNativeIndexRestorationLatencyMillis;
208     }
209 
210     /** Returns time used to recover the schema store. */
getSchemaStoreRecoveryLatencyMillis()211     public int getSchemaStoreRecoveryLatencyMillis() {
212         return mNativeSchemaStoreRecoveryLatencyMillis;
213     }
214 
215     /** Returns status about how much data is lost during the initialization. */
216     @DocumentStoreDataStatus
getDocumentStoreDataStatus()217     public int getDocumentStoreDataStatus() {
218         return mNativeDocumentStoreDataStatus;
219     }
220 
221     /**
222      * Returns number of documents currently in document store. Those may include alive, deleted,
223      * and expired documents.
224      */
getDocumentCount()225     public int getDocumentCount() {
226         return mNativeNumDocuments;
227     }
228 
229     /** Returns number of schema types currently in the schema store. */
getSchemaTypeCount()230     public int getSchemaTypeCount() {
231         return mNativeNumSchemaTypes;
232     }
233 
234     /** Returns whether we had to reset the index, losing all data, as part of initialization. */
hasReset()235     public boolean hasReset() {
236         return mHasReset;
237     }
238 
239     /**
240      * Returns the status of the reset, if one was performed according to {@link #hasReset}.
241      *
242      * <p>If no value has been set, the default value is {@link AppSearchResult#RESULT_OK}.
243      */
244     @AppSearchResult.ResultCode
getResetStatusCode()245     public int getResetStatusCode() {
246         return mResetStatusCode;
247     }
248 
InitializeStats(@onNull Builder builder)249     InitializeStats(@NonNull Builder builder) {
250         Objects.requireNonNull(builder);
251         mStatusCode = builder.mStatusCode;
252         mTotalLatencyMillis = builder.mTotalLatencyMillis;
253         mHasDeSync = builder.mHasDeSync;
254         mPrepareSchemaAndNamespacesLatencyMillis = builder.mPrepareSchemaAndNamespacesLatencyMillis;
255         mPrepareVisibilityStoreLatencyMillis = builder.mPrepareVisibilityStoreLatencyMillis;
256         mNativeLatencyMillis = builder.mNativeLatencyMillis;
257         mNativeDocumentStoreRecoveryCause = builder.mNativeDocumentStoreRecoveryCause;
258         mNativeIndexRestorationCause = builder.mNativeIndexRestorationCause;
259         mNativeSchemaStoreRecoveryCause = builder.mNativeSchemaStoreRecoveryCause;
260         mNativeDocumentStoreRecoveryLatencyMillis =
261                 builder.mNativeDocumentStoreRecoveryLatencyMillis;
262         mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis;
263         mNativeSchemaStoreRecoveryLatencyMillis = builder.mNativeSchemaStoreRecoveryLatencyMillis;
264         mNativeDocumentStoreDataStatus = builder.mNativeDocumentStoreDataStatus;
265         mNativeNumDocuments = builder.mNativeNumDocuments;
266         mNativeNumSchemaTypes = builder.mNativeNumSchemaTypes;
267         mHasReset = builder.mHasReset;
268         mResetStatusCode = builder.mResetStatusCode;
269     }
270 
271     /** Builder for {@link InitializeStats}. */
272     public static class Builder {
273         @AppSearchResult.ResultCode int mStatusCode;
274 
275         int mTotalLatencyMillis;
276         boolean mHasDeSync;
277         int mPrepareSchemaAndNamespacesLatencyMillis;
278         int mPrepareVisibilityStoreLatencyMillis;
279         int mNativeLatencyMillis;
280         @RecoveryCause int mNativeDocumentStoreRecoveryCause;
281         @RecoveryCause int mNativeIndexRestorationCause;
282         @RecoveryCause int mNativeSchemaStoreRecoveryCause;
283         int mNativeDocumentStoreRecoveryLatencyMillis;
284         int mNativeIndexRestorationLatencyMillis;
285         int mNativeSchemaStoreRecoveryLatencyMillis;
286         @DocumentStoreDataStatus int mNativeDocumentStoreDataStatus;
287         int mNativeNumDocuments;
288         int mNativeNumSchemaTypes;
289         boolean mHasReset;
290         @AppSearchResult.ResultCode int mResetStatusCode;
291 
292         /** Sets the status of the initialization. */
293         @CanIgnoreReturnValue
294         @NonNull
setStatusCode(@ppSearchResult.ResultCode int statusCode)295         public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) {
296             mStatusCode = statusCode;
297             return this;
298         }
299 
300         /** Sets the total latency of the initialization in milliseconds. */
301         @CanIgnoreReturnValue
302         @NonNull
setTotalLatencyMillis(int totalLatencyMillis)303         public Builder setTotalLatencyMillis(int totalLatencyMillis) {
304             mTotalLatencyMillis = totalLatencyMillis;
305             return this;
306         }
307 
308         /**
309          * Sets whether the initialize() detects deSync.
310          *
311          * <p>If there is a deSync, it means AppSearch and IcingSearchEngine have an inconsistent
312          * view of what data should exist.
313          */
314         @CanIgnoreReturnValue
315         @NonNull
setHasDeSync(boolean hasDeSync)316         public Builder setHasDeSync(boolean hasDeSync) {
317             mHasDeSync = hasDeSync;
318             return this;
319         }
320 
321         /** Sets time used to read and process the schema and namespaces. */
322         @CanIgnoreReturnValue
323         @NonNull
setPrepareSchemaAndNamespacesLatencyMillis( int prepareSchemaAndNamespacesLatencyMillis)324         public Builder setPrepareSchemaAndNamespacesLatencyMillis(
325                 int prepareSchemaAndNamespacesLatencyMillis) {
326             mPrepareSchemaAndNamespacesLatencyMillis = prepareSchemaAndNamespacesLatencyMillis;
327             return this;
328         }
329 
330         /** Sets time used to read and process the visibility file. */
331         @CanIgnoreReturnValue
332         @NonNull
setPrepareVisibilityStoreLatencyMillis( int prepareVisibilityStoreLatencyMillis)333         public Builder setPrepareVisibilityStoreLatencyMillis(
334                 int prepareVisibilityStoreLatencyMillis) {
335             mPrepareVisibilityStoreLatencyMillis = prepareVisibilityStoreLatencyMillis;
336             return this;
337         }
338 
339         /** Sets overall time used for the native function call. */
340         @CanIgnoreReturnValue
341         @NonNull
setNativeLatencyMillis(int nativeLatencyMillis)342         public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
343             mNativeLatencyMillis = nativeLatencyMillis;
344             return this;
345         }
346 
347         /**
348          * Sets recovery cause for document store.
349          *
350          * <p>Possible recovery causes for document store:
351          * <li>{@link InitializeStats#RECOVERY_CAUSE_DATA_LOSS}
352          * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
353          * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
354          */
355         @CanIgnoreReturnValue
356         @NonNull
setDocumentStoreRecoveryCause( @ecoveryCause int documentStoreRecoveryCause)357         public Builder setDocumentStoreRecoveryCause(
358                 @RecoveryCause int documentStoreRecoveryCause) {
359             mNativeDocumentStoreRecoveryCause = documentStoreRecoveryCause;
360             return this;
361         }
362 
363         /**
364          * Sets restoration cause for index store.
365          *
366          * <p>Possible causes:
367          * <li>{@link InitializeStats#DOCUMENT_STORE_DATA_STATUS_COMPLETE_LOSS}
368          * <li>{@link InitializeStats#RECOVERY_CAUSE_TOTAL_CHECKSUM_MISMATCH}
369          * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
370          */
371         @CanIgnoreReturnValue
372         @NonNull
setIndexRestorationCause(@ecoveryCause int indexRestorationCause)373         public Builder setIndexRestorationCause(@RecoveryCause int indexRestorationCause) {
374             mNativeIndexRestorationCause = indexRestorationCause;
375             return this;
376         }
377 
378         /**
379          * Returns recovery cause for schema store.
380          *
381          * <p>Possible causes:
382          * <li>{@link InitializeStats#RECOVERY_CAUSE_IO_ERROR}
383          */
384         @CanIgnoreReturnValue
385         @NonNull
setSchemaStoreRecoveryCause(@ecoveryCause int schemaStoreRecoveryCause)386         public Builder setSchemaStoreRecoveryCause(@RecoveryCause int schemaStoreRecoveryCause) {
387             mNativeSchemaStoreRecoveryCause = schemaStoreRecoveryCause;
388             return this;
389         }
390 
391         /** Sets time used to recover the document store. */
392         @CanIgnoreReturnValue
393         @NonNull
setDocumentStoreRecoveryLatencyMillis( int documentStoreRecoveryLatencyMillis)394         public Builder setDocumentStoreRecoveryLatencyMillis(
395                 int documentStoreRecoveryLatencyMillis) {
396             mNativeDocumentStoreRecoveryLatencyMillis = documentStoreRecoveryLatencyMillis;
397             return this;
398         }
399 
400         /** Sets time used to restore the index. */
401         @CanIgnoreReturnValue
402         @NonNull
setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis)403         public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) {
404             mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis;
405             return this;
406         }
407 
408         /** Sets time used to recover the schema store. */
409         @CanIgnoreReturnValue
410         @NonNull
setSchemaStoreRecoveryLatencyMillis(int schemaStoreRecoveryLatencyMillis)411         public Builder setSchemaStoreRecoveryLatencyMillis(int schemaStoreRecoveryLatencyMillis) {
412             mNativeSchemaStoreRecoveryLatencyMillis = schemaStoreRecoveryLatencyMillis;
413             return this;
414         }
415 
416         /**
417          * Sets Native Document Store Data status. status is defined in
418          * external/icing/proto/icing/proto/logging.proto
419          */
420         @CanIgnoreReturnValue
421         @NonNull
setDocumentStoreDataStatus( @ocumentStoreDataStatus int documentStoreDataStatus)422         public Builder setDocumentStoreDataStatus(
423                 @DocumentStoreDataStatus int documentStoreDataStatus) {
424             mNativeDocumentStoreDataStatus = documentStoreDataStatus;
425             return this;
426         }
427 
428         /**
429          * Sets number of documents currently in document store. Those may include alive, deleted,
430          * and expired documents.
431          */
432         @CanIgnoreReturnValue
433         @NonNull
setDocumentCount(int numDocuments)434         public Builder setDocumentCount(int numDocuments) {
435             mNativeNumDocuments = numDocuments;
436             return this;
437         }
438 
439         /** Sets number of schema types currently in the schema store. */
440         @CanIgnoreReturnValue
441         @NonNull
setSchemaTypeCount(int numSchemaTypes)442         public Builder setSchemaTypeCount(int numSchemaTypes) {
443             mNativeNumSchemaTypes = numSchemaTypes;
444             return this;
445         }
446 
447         /** Sets whether we had to reset the index, losing all data, as part of initialization. */
448         @CanIgnoreReturnValue
449         @NonNull
setHasReset(boolean hasReset)450         public Builder setHasReset(boolean hasReset) {
451             mHasReset = hasReset;
452             return this;
453         }
454 
455         /** Sets the status of the reset, if one was performed according to {@link #setHasReset}. */
456         @CanIgnoreReturnValue
457         @NonNull
setResetStatusCode(@ppSearchResult.ResultCode int resetStatusCode)458         public Builder setResetStatusCode(@AppSearchResult.ResultCode int resetStatusCode) {
459             mResetStatusCode = resetStatusCode;
460             return this;
461         }
462 
463         /**
464          * Constructs a new {@link InitializeStats} from the contents of this {@link
465          * InitializeStats.Builder}
466          */
467         @NonNull
build()468         public InitializeStats build() {
469             return new InitializeStats(/* builder= */ this);
470         }
471     }
472 }
473