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