From 410618472f0afaeb056aed5af8702e830d59cf9a Mon Sep 17 00:00:00 2001 From: Alexander Dorokhine Date: Mon, 12 Jul 2021 10:53:24 -0700 Subject: [PATCH] Log stats for Optimize OptimizeStats is crucial for us to tune our configuration for optimization, which might affect the health of AppSearch and system overall. Details can be found in Ib7ae475cc035d1b69969df1e22ac409895e0e3fa. Also add sampling parameters in AppSearchConfig for: 1) initializeStats 2) searchStats 3) globalSearchStats 4) optimizeStats Bug: 173532925 Bug: 175255572 Test: AppSearchStatsTest, FrameworksMockingServicesTests:AppSearchConfigTest, CtsAppSearchTestCases Ignore-AOSP-First: AppSearch is not available on AOSP yet Change-Id: Id61704407bdb40707cb8fa46b556024aea9f9083 --- .../server/appsearch/AppSearchConfig.java | 68 +++++ .../appsearch/AppSearchManagerService.java | 27 +- .../external/localstorage/AppSearchImpl.java | 24 +- .../localstorage/AppSearchLogger.java | 15 +- .../localstorage/AppSearchLoggerHelper.java | 34 ++- .../localstorage/stats/OptimizeStats.java | 243 ++++++++++++++++++ .../appsearch/stats/PlatformLogger.java | 50 +++- .../server/appsearch/AppSearchConfigTest.java | 97 +++++++ .../src/com/android/server/appsearch/OWNERS | 1 + .../localstorage/AppSearchImplTest.java | 12 +- .../localstorage/AppSearchLoggerTest.java | 50 ++++ .../stats/AppSearchStatsTest.java | 45 ++++ 12 files changed, 638 insertions(+), 28 deletions(-) create mode 100644 apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java index c44fd40617a1..29048b25ad6f 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchConfig.java @@ -81,6 +81,14 @@ public final class AppSearchConfig implements AutoCloseable { "sampling_interval_for_batch_call_stats"; public static final String KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS = "sampling_interval_for_put_document_stats"; + public static final String KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS = + "sampling_interval_for_initialize_stats"; + public static final String KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS = + "sampling_interval_for_search_stats"; + public static final String KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS = + "sampling_interval_for_global_search_stats"; + public static final String KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS = + "sampling_interval_for_optimize_stats"; public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES = "limit_config_max_document_size_bytes"; public static final String KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT = @@ -95,6 +103,10 @@ public final class AppSearchConfig implements AutoCloseable { KEY_SAMPLING_INTERVAL_DEFAULT, KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS, + KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS, + KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS, + KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS, + KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS, KEY_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES, KEY_LIMIT_CONFIG_MAX_DOCUMENT_COUNT, KEY_BYTES_OPTIMIZE_THRESHOLD, @@ -245,6 +257,58 @@ public final class AppSearchConfig implements AutoCloseable { } } + /** + * Returns cached value for sampling interval for initialize. + * + *

For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForInitializeStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS, + getCachedSamplingIntervalDefault()); + } + } + + /** + * Returns cached value for sampling interval for search. + * + *

For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForSearchStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS, + getCachedSamplingIntervalDefault()); + } + } + + /** + * Returns cached value for sampling interval for globalSearch. + * + *

For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForGlobalSearchStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS, + getCachedSamplingIntervalDefault()); + } + } + + /** + * Returns cached value for sampling interval for optimize. + * + *

For example, sampling_interval=10 means that one out of every 10 stats was logged. + */ + public int getCachedSamplingIntervalForOptimizeStats() { + synchronized (mLock) { + throwIfClosedLocked(); + return mBundleLocked.getInt(KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS, + getCachedSamplingIntervalDefault()); + } + } + /** Returns the maximum serialized size an indexed document can be, in bytes. */ public int getCachedLimitConfigMaxDocumentSizeBytes() { synchronized (mLock) { @@ -343,6 +407,10 @@ public final class AppSearchConfig implements AutoCloseable { case KEY_SAMPLING_INTERVAL_DEFAULT: case KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS: case KEY_SAMPLING_INTERVAL_FOR_PUT_DOCUMENT_STATS: + case KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS: + case KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS: + case KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS: + case KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS: synchronized (mLock) { mBundleLocked.putInt(key, properties.getInt(key, DEFAULT_SAMPLING_INTERVAL)); } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java index b52a503a2166..80f65f841350 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java @@ -60,6 +60,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.server.LocalManagerRegistry; import com.android.server.SystemService; import com.android.server.appsearch.external.localstorage.stats.CallStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore; import com.android.server.appsearch.stats.StatsCollector; import com.android.server.appsearch.util.PackageUtil; @@ -1497,20 +1498,42 @@ public class AppSearchManagerService extends SystemService { private void checkForOptimize(AppSearchUserInstance instance, int mutateBatchSize) { EXECUTOR.execute(() -> { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + OptimizeStats.Builder builder = new OptimizeStats.Builder(); try { - instance.getAppSearchImpl().checkForOptimize(mutateBatchSize); + instance.getAppSearchImpl().checkForOptimize(mutateBatchSize, builder); } catch (AppSearchException e) { Log.w(TAG, "Error occurred when check for optimize", e); + } finally { + OptimizeStats oStats = builder + .setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)) + .build(); + if (oStats.getOriginalDocumentCount() > 0) { + // see if optimize has been run by checking originalDocumentCount + instance.getLogger().logStats(oStats); + } } }); } private void checkForOptimize(AppSearchUserInstance instance) { EXECUTOR.execute(() -> { + long totalLatencyStartMillis = SystemClock.elapsedRealtime(); + OptimizeStats.Builder builder = new OptimizeStats.Builder(); try { - instance.getAppSearchImpl().checkForOptimize(); + instance.getAppSearchImpl().checkForOptimize(builder); } catch (AppSearchException e) { Log.w(TAG, "Error occurred when check for optimize", e); + } finally { + OptimizeStats oStats = builder + .setTotalLatencyMillis( + (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis)) + .build(); + if (oStats.getOriginalDocumentCount() > 0) { + // see if optimize has been run by checking originalDocumentCount + instance.getLogger().logStats(oStats); + } } }); } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java index a1b93ce12975..dd6a79e8eeac 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java @@ -55,6 +55,7 @@ import com.android.server.appsearch.external.localstorage.converter.SearchSpecTo import com.android.server.appsearch.external.localstorage.converter.SetSchemaResponseToProtoConverter; import com.android.server.appsearch.external.localstorage.converter.TypePropertyPathToProtoConverter; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; @@ -269,6 +270,9 @@ public final class AppSearchImpl implements Closeable { // Log the time it took to read the data that goes into the cache maps if (initStatsBuilder != null) { + // In case there is some error for getAllNamespaces, we can still + // set the latency for preparation. + // If there is no error, the value will be overridden by the actual one later. initStatsBuilder .setStatusCode( statusProtoToResultCode( @@ -1292,8 +1296,7 @@ public final class AppSearchImpl implements Closeable { deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND); // Update derived maps - int numDocumentsDeleted = - deleteResultProto.getDeleteStats().getNumDocumentsDeleted(); + int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted(); updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted); } finally { mReadWriteLock.writeLock().unlock(); @@ -2096,12 +2099,13 @@ public final class AppSearchImpl implements Closeable { * #CHECK_OPTIMIZE_INTERVAL}, {@link IcingSearchEngine#getOptimizeInfo()} will be triggered * and the counter will be reset. */ - public void checkForOptimize(int mutationSize) throws AppSearchException { + public void checkForOptimize(int mutationSize, @Nullable OptimizeStats.Builder builder) + throws AppSearchException { mReadWriteLock.writeLock().lock(); try { mOptimizeIntervalCountLocked += mutationSize; if (mOptimizeIntervalCountLocked >= CHECK_OPTIMIZE_INTERVAL) { - checkForOptimize(); + checkForOptimize(builder); } } finally { mReadWriteLock.writeLock().unlock(); @@ -2117,14 +2121,15 @@ public final class AppSearchImpl implements Closeable { *

{@link IcingSearchEngine#optimize()} should be called only if {@link * OptimizeStrategy#shouldOptimize(GetOptimizeInfoResultProto)} return true. */ - public void checkForOptimize() throws AppSearchException { + public void checkForOptimize(@Nullable OptimizeStats.Builder builder) + throws AppSearchException { mReadWriteLock.writeLock().lock(); try { GetOptimizeInfoResultProto optimizeInfo = getOptimizeInfoResultLocked(); checkSuccess(optimizeInfo.getStatus()); mOptimizeIntervalCountLocked = 0; if (mOptimizeStrategy.shouldOptimize(optimizeInfo)) { - optimize(); + optimize(builder); } } finally { mReadWriteLock.writeLock().unlock(); @@ -2135,13 +2140,18 @@ public final class AppSearchImpl implements Closeable { } /** Triggers {@link IcingSearchEngine#optimize()} directly. */ - public void optimize() throws AppSearchException { + public void optimize(@Nullable OptimizeStats.Builder builder) throws AppSearchException { mReadWriteLock.writeLock().lock(); try { mLogUtil.piiTrace("optimize, request"); OptimizeResultProto optimizeResultProto = mIcingSearchEngineLocked.optimize(); mLogUtil.piiTrace( "optimize, response", optimizeResultProto.getStatus(), optimizeResultProto); + if (builder != null) { + builder.setStatusCode(statusProtoToResultCode(optimizeResultProto.getStatus())); + AppSearchLoggerHelper.copyNativeStats( + optimizeResultProto.getOptimizeStats(), builder); + } checkSuccess(optimizeResultProto.getStatus()); } finally { mReadWriteLock.writeLock().unlock(); diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java index d92f4f05a1a4..98cedc7e6b54 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java @@ -17,10 +17,10 @@ package com.android.server.appsearch.external.localstorage; import android.annotation.NonNull; -import android.app.appsearch.exceptions.AppSearchException; import com.android.server.appsearch.external.localstorage.stats.CallStats; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; @@ -37,19 +37,22 @@ import com.android.server.appsearch.external.localstorage.stats.SearchStats; */ public interface AppSearchLogger { /** Logs {@link CallStats} */ - void logStats(@NonNull CallStats stats) throws AppSearchException; + void logStats(@NonNull CallStats stats); /** Logs {@link PutDocumentStats} */ - void logStats(@NonNull PutDocumentStats stats) throws AppSearchException; + void logStats(@NonNull PutDocumentStats stats); /** Logs {@link InitializeStats} */ - void logStats(@NonNull InitializeStats stats) throws AppSearchException; + void logStats(@NonNull InitializeStats stats); /** Logs {@link SearchStats} */ - void logStats(@NonNull SearchStats stats) throws AppSearchException; + void logStats(@NonNull SearchStats stats); /** Logs {@link RemoveStats} */ - void logStats(@NonNull RemoveStats stats) throws AppSearchException; + void logStats(@NonNull RemoveStats stats); + + /** Logs {@link OptimizeStats} */ + void logStats(@NonNull OptimizeStats stats); // TODO(b/173532925) Add remaining logStats once we add all the stats. } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java index aa9200abe3be..cd653e569f11 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java @@ -19,12 +19,14 @@ package com.android.server.appsearch.external.localstorage; import android.annotation.NonNull; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; import com.google.android.icing.proto.DeleteStatsProto; import com.google.android.icing.proto.InitializeStatsProto; +import com.google.android.icing.proto.OptimizeStatsProto; import com.google.android.icing.proto.PutDocumentStatsProto; import com.google.android.icing.proto.QueryStatsProto; @@ -92,8 +94,8 @@ public final class AppSearchLoggerHelper { .setSchemaTypeCount(fromNativeStats.getNumSchemaTypes()); } - /* - * Copy native Query stats to buiilder. + /** + * Copies native Query stats to builder. * * @param fromNativeStats Stats copied from. * @param toStatsBuilder Stats copied to. @@ -122,8 +124,8 @@ public final class AppSearchLoggerHelper { fromNativeStats.getDocumentRetrievalLatencyMs()); } - /* - * Copy native Query stats to buiilder. + /** + * Copies native Delete stats to builder. * * @param fromNativeStats Stats copied from. * @param toStatsBuilder Stats copied to. @@ -138,4 +140,28 @@ public final class AppSearchLoggerHelper { .setDeleteType(fromNativeStats.getDeleteType().getNumber()) .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted()); } + + /** + * Copies native {@link OptimizeStatsProto} to builder. + * + * @param fromNativeStats Stats copied from. + * @param toStatsBuilder Stats copied to. + */ + static void copyNativeStats( + @NonNull OptimizeStatsProto fromNativeStats, + @NonNull OptimizeStats.Builder toStatsBuilder) { + Objects.requireNonNull(fromNativeStats); + Objects.requireNonNull(toStatsBuilder); + toStatsBuilder + .setNativeLatencyMillis(fromNativeStats.getLatencyMs()) + .setDocumentStoreOptimizeLatencyMillis( + fromNativeStats.getDocumentStoreOptimizeLatencyMs()) + .setIndexRestorationLatencyMillis(fromNativeStats.getIndexRestorationLatencyMs()) + .setOriginalDocumentCount(fromNativeStats.getNumOriginalDocuments()) + .setDeletedDocumentCount(fromNativeStats.getNumDeletedDocuments()) + .setExpiredDocumentCount(fromNativeStats.getNumExpiredDocuments()) + .setStorageSizeBeforeBytes(fromNativeStats.getStorageSizeBefore()) + .setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter()) + .setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs()); + } } diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java new file mode 100644 index 000000000000..83bd50f92e3b --- /dev/null +++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/OptimizeStats.java @@ -0,0 +1,243 @@ +/* + * Copyright 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.appsearch.external.localstorage.stats; + +import android.annotation.NonNull; +import android.app.appsearch.AppSearchResult; + +import java.util.Objects; + +/** + * Class holds detailed stats for Optimize. + * + * @hide + */ +public final class OptimizeStats { + /** + * The status code returned by {@link AppSearchResult#getResultCode()} for the call or internal + * state. + */ + @AppSearchResult.ResultCode private final int mStatusCode; + + private final int mTotalLatencyMillis; + private final int mNativeLatencyMillis; + + // Time used to optimize the document store in millis. + private final int mNativeDocumentStoreOptimizeLatencyMillis; + + // Time used to restore the index in millis. + private final int mNativeIndexRestorationLatencyMillis; + + // Number of documents before the optimization. + private final int mNativeOriginalDocumentCount; + + // Number of documents deleted during the optimization. + private final int mNativeDeletedDocumentCount; + + // Number of documents expired during the optimization. + private final int mNativeExpiredDocumentCount; + + // Size of storage in bytes before the optimization. + private final long mNativeStorageSizeBeforeBytes; + + // Size of storage in bytes after the optimization. + private final long mNativeStorageSizeAfterBytes; + + // The amount of time in millis since the last optimization ran calculated using wall clock time + private final long mNativeTimeSinceLastOptimizeMillis; + + OptimizeStats(@NonNull Builder builder) { + Objects.requireNonNull(builder); + mStatusCode = builder.mStatusCode; + mTotalLatencyMillis = builder.mTotalLatencyMillis; + mNativeLatencyMillis = builder.mNativeLatencyMillis; + mNativeDocumentStoreOptimizeLatencyMillis = + builder.mNativeDocumentStoreOptimizeLatencyMillis; + mNativeIndexRestorationLatencyMillis = builder.mNativeIndexRestorationLatencyMillis; + mNativeOriginalDocumentCount = builder.mNativeOriginalDocumentCount; + mNativeDeletedDocumentCount = builder.mNativeDeletedDocumentCount; + mNativeExpiredDocumentCount = builder.mNativeExpiredDocumentCount; + mNativeStorageSizeBeforeBytes = builder.mNativeStorageSizeBeforeBytes; + mNativeStorageSizeAfterBytes = builder.mNativeStorageSizeAfterBytes; + mNativeTimeSinceLastOptimizeMillis = builder.mNativeTimeSinceLastOptimizeMillis; + } + + /** Returns status code for this optimization. */ + @AppSearchResult.ResultCode + public int getStatusCode() { + return mStatusCode; + } + + /** Returns total latency of this optimization in millis. */ + public int getTotalLatencyMillis() { + return mTotalLatencyMillis; + } + + /** Returns how much time in millis spent in the native code. */ + public int getNativeLatencyMillis() { + return mNativeLatencyMillis; + } + + /** Returns time used to optimize the document store in millis. */ + public int getDocumentStoreOptimizeLatencyMillis() { + return mNativeDocumentStoreOptimizeLatencyMillis; + } + + /** Returns time used to restore the index in millis. */ + public int getIndexRestorationLatencyMillis() { + return mNativeIndexRestorationLatencyMillis; + } + + /** Returns number of documents before the optimization. */ + public int getOriginalDocumentCount() { + return mNativeOriginalDocumentCount; + } + + /** Returns number of documents deleted during the optimization. */ + public int getDeletedDocumentCount() { + return mNativeDeletedDocumentCount; + } + + /** Returns number of documents expired during the optimization. */ + public int getExpiredDocumentCount() { + return mNativeExpiredDocumentCount; + } + + /** Returns size of storage in bytes before the optimization. */ + public long getStorageSizeBeforeBytes() { + return mNativeStorageSizeBeforeBytes; + } + + /** Returns size of storage in bytes after the optimization. */ + public long getStorageSizeAfterBytes() { + return mNativeStorageSizeAfterBytes; + } + + /** + * Returns the amount of time in millis since the last optimization ran calculated using wall + * clock time. + */ + public long getTimeSinceLastOptimizeMillis() { + return mNativeTimeSinceLastOptimizeMillis; + } + + /** Builder for {@link RemoveStats}. */ + public static class Builder { + /** + * The status code returned by {@link AppSearchResult#getResultCode()} for the call or + * internal state. + */ + @AppSearchResult.ResultCode int mStatusCode; + + int mTotalLatencyMillis; + int mNativeLatencyMillis; + int mNativeDocumentStoreOptimizeLatencyMillis; + int mNativeIndexRestorationLatencyMillis; + int mNativeOriginalDocumentCount; + int mNativeDeletedDocumentCount; + int mNativeExpiredDocumentCount; + long mNativeStorageSizeBeforeBytes; + long mNativeStorageSizeAfterBytes; + long mNativeTimeSinceLastOptimizeMillis; + + /** Sets the status code. */ + @NonNull + public Builder setStatusCode(@AppSearchResult.ResultCode int statusCode) { + mStatusCode = statusCode; + return this; + } + + /** Sets total latency in millis. */ + @NonNull + public Builder setTotalLatencyMillis(int totalLatencyMillis) { + mTotalLatencyMillis = totalLatencyMillis; + return this; + } + + /** Sets native latency in millis. */ + @NonNull + public Builder setNativeLatencyMillis(int nativeLatencyMillis) { + mNativeLatencyMillis = nativeLatencyMillis; + return this; + } + + /** Sets time used to optimize the document store. */ + @NonNull + public Builder setDocumentStoreOptimizeLatencyMillis( + int documentStoreOptimizeLatencyMillis) { + mNativeDocumentStoreOptimizeLatencyMillis = documentStoreOptimizeLatencyMillis; + return this; + } + + /** Sets time used to restore the index. */ + @NonNull + public Builder setIndexRestorationLatencyMillis(int indexRestorationLatencyMillis) { + mNativeIndexRestorationLatencyMillis = indexRestorationLatencyMillis; + return this; + } + + /** Sets number of documents before the optimization. */ + @NonNull + public Builder setOriginalDocumentCount(int originalDocumentCount) { + mNativeOriginalDocumentCount = originalDocumentCount; + return this; + } + + /** Sets number of documents deleted during the optimization. */ + @NonNull + public Builder setDeletedDocumentCount(int deletedDocumentCount) { + mNativeDeletedDocumentCount = deletedDocumentCount; + return this; + } + + /** Sets number of documents expired during the optimization. */ + @NonNull + public Builder setExpiredDocumentCount(int expiredDocumentCount) { + mNativeExpiredDocumentCount = expiredDocumentCount; + return this; + } + + /** Sets Storage size in bytes before optimization. */ + @NonNull + public Builder setStorageSizeBeforeBytes(long storageSizeBeforeBytes) { + mNativeStorageSizeBeforeBytes = storageSizeBeforeBytes; + return this; + } + + /** Sets storage size in bytes after optimization. */ + @NonNull + public Builder setStorageSizeAfterBytes(long storageSizeAfterBytes) { + mNativeStorageSizeAfterBytes = storageSizeAfterBytes; + return this; + } + + /** + * Sets the amount the time since the last optimize ran calculated using wall clock time. + */ + @NonNull + public Builder setTimeSinceLastOptimizeMillis(long timeSinceLastOptimizeMillis) { + mNativeTimeSinceLastOptimizeMillis = timeSinceLastOptimizeMillis; + return this; + } + + /** Creates a {@link OptimizeStats}. */ + @NonNull + public OptimizeStats build() { + return new OptimizeStats(/* builder= */ this); + } + } +} diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java index 2cbce106932d..fdf6a008b10c 100644 --- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java +++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java @@ -32,6 +32,7 @@ import com.android.server.appsearch.AppSearchConfig; import com.android.server.appsearch.external.localstorage.AppSearchLogger; import com.android.server.appsearch.external.localstorage.stats.CallStats; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; @@ -145,7 +146,7 @@ public final class PlatformLogger implements AppSearchLogger { } @Override - public void logStats(@NonNull InitializeStats stats) throws AppSearchException { + public void logStats(@NonNull InitializeStats stats) { Objects.requireNonNull(stats); synchronized (mLock) { if (shouldLogForTypeLocked(CallStats.CALL_TYPE_INITIALIZE)) { @@ -155,7 +156,7 @@ public final class PlatformLogger implements AppSearchLogger { } @Override - public void logStats(@NonNull SearchStats stats) throws AppSearchException { + public void logStats(@NonNull SearchStats stats) { Objects.requireNonNull(stats); synchronized (mLock) { if (shouldLogForTypeLocked(CallStats.CALL_TYPE_SEARCH)) { @@ -165,10 +166,20 @@ public final class PlatformLogger implements AppSearchLogger { } @Override - public void logStats(@NonNull RemoveStats stats) throws AppSearchException { + public void logStats(@NonNull RemoveStats stats) { // TODO(b/173532925): Log stats } + @Override + public void logStats(@NonNull OptimizeStats stats) { + Objects.requireNonNull(stats); + synchronized (mLock) { + if (shouldLogForTypeLocked(CallStats.CALL_TYPE_OPTIMIZE)) { + logStatsImplLocked(stats); + } + } + } + /** * Removes cached UID for package. * @@ -326,6 +337,27 @@ public final class PlatformLogger implements AppSearchLogger { stats.getResetStatusCode()); } + @GuardedBy("mLock") + private void logStatsImplLocked(@NonNull OptimizeStats stats) { + mLastPushTimeMillisLocked = SystemClock.elapsedRealtime(); + ExtraStats extraStats = createExtraStatsLocked(/*packageName=*/ null, + CallStats.CALL_TYPE_OPTIMIZE); + AppSearchStatsLog.write(AppSearchStatsLog.APP_SEARCH_OPTIMIZE_STATS_REPORTED, + extraStats.mSamplingInterval, + extraStats.mSkippedSampleCount, + stats.getStatusCode(), + stats.getTotalLatencyMillis(), + stats.getNativeLatencyMillis(), + stats.getDocumentStoreOptimizeLatencyMillis(), + stats.getIndexRestorationLatencyMillis(), + stats.getOriginalDocumentCount(), + stats.getDeletedDocumentCount(), + stats.getExpiredDocumentCount(), + stats.getStorageSizeBeforeBytes(), + stats.getStorageSizeAfterBytes(), + stats.getTimeSinceLastOptimizeMillis()); + } + /** * Calculate the hash code as an integer by returning the last four bytes of its MD5. * @@ -464,15 +496,19 @@ public final class PlatformLogger implements AppSearchLogger { return mConfig.getCachedSamplingIntervalForBatchCallStats(); case CallStats.CALL_TYPE_PUT_DOCUMENT: return mConfig.getCachedSamplingIntervalForPutDocumentStats(); - case CallStats.CALL_TYPE_UNKNOWN: case CallStats.CALL_TYPE_INITIALIZE: + return mConfig.getCachedSamplingIntervalForInitializeStats(); + case CallStats.CALL_TYPE_SEARCH: + return mConfig.getCachedSamplingIntervalForSearchStats(); + case CallStats.CALL_TYPE_GLOBAL_SEARCH: + return mConfig.getCachedSamplingIntervalForGlobalSearchStats(); + case CallStats.CALL_TYPE_OPTIMIZE: + return mConfig.getCachedSamplingIntervalForOptimizeStats(); + case CallStats.CALL_TYPE_UNKNOWN: case CallStats.CALL_TYPE_SET_SCHEMA: case CallStats.CALL_TYPE_GET_DOCUMENT: case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_ID: - case CallStats.CALL_TYPE_SEARCH: - case CallStats.CALL_TYPE_OPTIMIZE: case CallStats.CALL_TYPE_FLUSH: - case CallStats.CALL_TYPE_GLOBAL_SEARCH: case CallStats.CALL_TYPE_REMOVE_DOCUMENT_BY_SEARCH: // TODO(b/173532925) Some of them above will have dedicated sampling ratio config default: diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java index 8336663d4dd1..9926953f110f 100644 --- a/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/AppSearchConfigTest.java @@ -50,6 +50,14 @@ public class AppSearchConfigTest { AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); assertThat(appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()).isEqualTo( AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); + assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo( + AppSearchConfig.DEFAULT_SAMPLING_INTERVAL); assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentSizeBytes()).isEqualTo( AppSearchConfig.DEFAULT_LIMIT_CONFIG_MAX_DOCUMENT_SIZE_BYTES); assertThat(appSearchConfig.getCachedLimitConfigMaxDocumentCount()).isEqualTo( @@ -100,6 +108,11 @@ public class AppSearchConfigTest { final int samplingIntervalDefault = -1; final int samplingIntervalPutDocumentStats = -2; final int samplingIntervalBatchCallStats = -3; + final int samplingIntervalInitializeStats = -4; + final int samplingIntervalSearchStats = -5; + final int samplingIntervalGlobalSearchStats = -6; + final int samplingIntervalOptimizeStats = -7; + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, Integer.toString(samplingIntervalDefault), @@ -112,6 +125,22 @@ public class AppSearchConfigTest { AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, Integer.toString(samplingIntervalBatchCallStats), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS, + Integer.toString(samplingIntervalInitializeStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS, + Integer.toString(samplingIntervalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS, + Integer.toString(samplingIntervalGlobalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS, + Integer.toString(samplingIntervalOptimizeStats), + false); AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); @@ -121,6 +150,14 @@ public class AppSearchConfigTest { samplingIntervalPutDocumentStats); assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( samplingIntervalBatchCallStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo( + samplingIntervalInitializeStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo( + samplingIntervalSearchStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo( + samplingIntervalGlobalSearchStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo( + samplingIntervalOptimizeStats); } @Test @@ -128,6 +165,10 @@ public class AppSearchConfigTest { int samplingIntervalDefault = -1; int samplingIntervalPutDocumentStats = -2; int samplingIntervalBatchCallStats = -3; + int samplingIntervalInitializeStats = -4; + int samplingIntervalSearchStats = -5; + int samplingIntervalGlobalSearchStats = -6; + int samplingIntervalOptimizeStats = -7; DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, Integer.toString(samplingIntervalDefault), @@ -140,12 +181,32 @@ public class AppSearchConfigTest { AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, Integer.toString(samplingIntervalBatchCallStats), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS, + Integer.toString(samplingIntervalInitializeStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS, + Integer.toString(samplingIntervalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS, + Integer.toString(samplingIntervalGlobalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS, + Integer.toString(samplingIntervalOptimizeStats), + false); AppSearchConfig appSearchConfig = AppSearchConfig.create(DIRECT_EXECUTOR); // Overrides samplingIntervalDefault = -4; samplingIntervalPutDocumentStats = -5; samplingIntervalBatchCallStats = -6; + samplingIntervalInitializeStats = -7; + samplingIntervalSearchStats = -8; + samplingIntervalGlobalSearchStats = -9; + samplingIntervalOptimizeStats = -10; DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, AppSearchConfig.KEY_SAMPLING_INTERVAL_DEFAULT, Integer.toString(samplingIntervalDefault), @@ -158,6 +219,22 @@ public class AppSearchConfigTest { AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_BATCH_CALL_STATS, Integer.toString(samplingIntervalBatchCallStats), false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_INITIALIZE_STATS, + Integer.toString(samplingIntervalInitializeStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_SEARCH_STATS, + Integer.toString(samplingIntervalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_GLOBAL_SEARCH_STATS, + Integer.toString(samplingIntervalGlobalSearchStats), + false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_APPSEARCH, + AppSearchConfig.KEY_SAMPLING_INTERVAL_FOR_OPTIMIZE_STATS, + Integer.toString(samplingIntervalOptimizeStats), + false); assertThat(appSearchConfig.getCachedSamplingIntervalDefault()).isEqualTo( samplingIntervalDefault); @@ -165,6 +242,14 @@ public class AppSearchConfigTest { samplingIntervalPutDocumentStats); assertThat(appSearchConfig.getCachedSamplingIntervalForBatchCallStats()).isEqualTo( samplingIntervalBatchCallStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForInitializeStats()).isEqualTo( + samplingIntervalInitializeStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForSearchStats()).isEqualTo( + samplingIntervalSearchStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()).isEqualTo( + samplingIntervalGlobalSearchStats); + assertThat(appSearchConfig.getCachedSamplingIntervalForOptimizeStats()).isEqualTo( + samplingIntervalOptimizeStats); } /** @@ -364,6 +449,18 @@ public class AppSearchConfigTest { Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", IllegalStateException.class, () -> appSearchConfig.getCachedSamplingIntervalForPutDocumentStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForInitializeStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForSearchStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForGlobalSearchStats()); + Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", + IllegalStateException.class, + () -> appSearchConfig.getCachedSamplingIntervalForOptimizeStats()); Assert.assertThrows("Trying to use a closed AppSearchConfig instance.", IllegalStateException.class, () -> appSearchConfig.getCachedBytesOptimizeThreshold()); diff --git a/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS b/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS new file mode 100644 index 000000000000..24f6b0b6b2b6 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/appsearch/OWNERS @@ -0,0 +1 @@ +include /apex/appsearch/OWNERS \ No newline at end of file diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java index 91f49224fde8..d808b8bbdd2f 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java @@ -42,6 +42,7 @@ import androidx.test.core.app.ApplicationProvider; import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.util.PrefixUtil; import com.android.server.appsearch.icing.proto.DocumentProto; import com.android.server.appsearch.icing.proto.GetOptimizeInfoResultProto; @@ -451,19 +452,26 @@ public class AppSearchImplTest { assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1); // Increase mutation counter and stop before reach the threshold - mAppSearchImpl.checkForOptimize(AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1); + mAppSearchImpl.checkForOptimize( + AppSearchImpl.CHECK_OPTIMIZE_INTERVAL - 1, /*builder=*/ null); // Verify the optimize() isn't triggered. optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked(); assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(1); // Increase the counter and reach the threshold, optimize() should be triggered. - mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1); + OptimizeStats.Builder builder = new OptimizeStats.Builder(); + mAppSearchImpl.checkForOptimize(/*mutateBatchSize=*/ 1, builder); // Verify optimize() is triggered. optimizeInfo = mAppSearchImpl.getOptimizeInfoResultLocked(); assertThat(optimizeInfo.getOptimizableDocs()).isEqualTo(0); assertThat(optimizeInfo.getEstimatedOptimizableBytes()).isEqualTo(0); + + // Verify the stats have been set. + OptimizeStats oStats = builder.build(); + assertThat(oStats.getOriginalDocumentCount()).isEqualTo(1); + assertThat(oStats.getDeletedDocumentCount()).isEqualTo(1); } @Test diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java index 7bacbb63f10c..7c976876a731 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java @@ -29,12 +29,14 @@ import android.app.appsearch.exceptions.AppSearchException; import com.android.server.appsearch.external.localstorage.stats.CallStats; import com.android.server.appsearch.external.localstorage.stats.InitializeStats; +import com.android.server.appsearch.external.localstorage.stats.OptimizeStats; import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats; import com.android.server.appsearch.external.localstorage.stats.RemoveStats; import com.android.server.appsearch.external.localstorage.stats.SearchStats; import com.android.server.appsearch.icing.proto.DeleteStatsProto; import com.android.server.appsearch.icing.proto.DocumentProto; import com.android.server.appsearch.icing.proto.InitializeStatsProto; +import com.android.server.appsearch.icing.proto.OptimizeStatsProto; import com.android.server.appsearch.icing.proto.PutDocumentStatsProto; import com.android.server.appsearch.icing.proto.PutResultProto; import com.android.server.appsearch.icing.proto.QueryStatsProto; @@ -81,6 +83,7 @@ public class AppSearchLoggerTest { @Nullable InitializeStats mInitializeStats; @Nullable SearchStats mSearchStats; @Nullable RemoveStats mRemoveStats; + @Nullable OptimizeStats mOptimizeStats; @Override public void logStats(@NonNull CallStats stats) { @@ -106,6 +109,11 @@ public class AppSearchLoggerTest { public void logStats(@NonNull RemoveStats stats) { mRemoveStats = stats; } + + @Override + public void logStats(@NonNull OptimizeStats stats) { + mOptimizeStats = stats; + } } @Test @@ -286,6 +294,48 @@ public class AppSearchLoggerTest { assertThat(rStats.getDeletedDocumentCount()).isEqualTo(nativeNumDocumentDeleted); } + @Test + public void testAppSearchLoggerHelper_testCopyNativeStats_optimize() { + int nativeLatencyMillis = 1; + int nativeDocumentStoreOptimizeLatencyMillis = 2; + int nativeIndexRestorationLatencyMillis = 3; + int nativeNumOriginalDocuments = 4; + int nativeNumDeletedDocuments = 5; + int nativeNumExpiredDocuments = 6; + long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1; + long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2; + long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3; + OptimizeStatsProto optimizeStatsProto = + OptimizeStatsProto.newBuilder() + .setLatencyMs(nativeLatencyMillis) + .setDocumentStoreOptimizeLatencyMs(nativeDocumentStoreOptimizeLatencyMillis) + .setIndexRestorationLatencyMs(nativeIndexRestorationLatencyMillis) + .setNumOriginalDocuments(nativeNumOriginalDocuments) + .setNumDeletedDocuments(nativeNumDeletedDocuments) + .setNumExpiredDocuments(nativeNumExpiredDocuments) + .setStorageSizeBefore(nativeStorageSizeBeforeBytes) + .setStorageSizeAfter(nativeStorageSizeAfterBytes) + .setTimeSinceLastOptimizeMs(nativeTimeSinceLastOptimizeMillis) + .build(); + OptimizeStats.Builder oBuilder = new OptimizeStats.Builder(); + + AppSearchLoggerHelper.copyNativeStats(optimizeStatsProto, oBuilder); + + OptimizeStats oStats = oBuilder.build(); + assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(oStats.getDocumentStoreOptimizeLatencyMillis()) + .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis); + assertThat(oStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments); + assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments); + assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments); + assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes); + assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes); + assertThat(oStats.getTimeSinceLastOptimizeMillis()) + .isEqualTo(nativeTimeSinceLastOptimizeMillis); + } + // // Testing actual logging // diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java index 57d994155d5b..c1dc0e447c70 100644 --- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java +++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java @@ -348,4 +348,49 @@ public class AppSearchStatsTest { assertThat(rStats.getDeleteType()).isEqualTo(deleteType); assertThat(rStats.getDeletedDocumentCount()).isEqualTo(documentDeletedCount); } + + @Test + public void testAppSearchStats_OptimizeStats() { + int nativeLatencyMillis = 1; + int nativeDocumentStoreOptimizeLatencyMillis = 2; + int nativeIndexRestorationLatencyMillis = 3; + int nativeNumOriginalDocuments = 4; + int nativeNumDeletedDocuments = 5; + int nativeNumExpiredDocuments = 6; + long nativeStorageSizeBeforeBytes = Integer.MAX_VALUE + 1; + long nativeStorageSizeAfterBytes = Integer.MAX_VALUE + 2; + long nativeTimeSinceLastOptimizeMillis = Integer.MAX_VALUE + 3; + + final OptimizeStats oStats = + new OptimizeStats.Builder() + .setStatusCode(TEST_STATUS_CODE) + .setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS) + .setNativeLatencyMillis(nativeLatencyMillis) + .setDocumentStoreOptimizeLatencyMillis( + nativeDocumentStoreOptimizeLatencyMillis) + .setIndexRestorationLatencyMillis(nativeIndexRestorationLatencyMillis) + .setOriginalDocumentCount(nativeNumOriginalDocuments) + .setDeletedDocumentCount(nativeNumDeletedDocuments) + .setExpiredDocumentCount(nativeNumExpiredDocuments) + .setStorageSizeBeforeBytes(nativeStorageSizeBeforeBytes) + .setStorageSizeAfterBytes(nativeStorageSizeAfterBytes) + .setTimeSinceLastOptimizeMillis(nativeTimeSinceLastOptimizeMillis) + .build(); + + assertThat(oStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE); + assertThat(oStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS); + assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(oStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis); + assertThat(oStats.getDocumentStoreOptimizeLatencyMillis()) + .isEqualTo(nativeDocumentStoreOptimizeLatencyMillis); + assertThat(oStats.getIndexRestorationLatencyMillis()) + .isEqualTo(nativeIndexRestorationLatencyMillis); + assertThat(oStats.getOriginalDocumentCount()).isEqualTo(nativeNumOriginalDocuments); + assertThat(oStats.getDeletedDocumentCount()).isEqualTo(nativeNumDeletedDocuments); + assertThat(oStats.getExpiredDocumentCount()).isEqualTo(nativeNumExpiredDocuments); + assertThat(oStats.getStorageSizeBeforeBytes()).isEqualTo(nativeStorageSizeBeforeBytes); + assertThat(oStats.getStorageSizeAfterBytes()).isEqualTo(nativeStorageSizeAfterBytes); + assertThat(oStats.getTimeSinceLastOptimizeMillis()) + .isEqualTo(nativeTimeSinceLastOptimizeMillis); + } }