mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-05-25 17:45:12 +01:00
Improve perf for backup info in debuglogs.
This commit is contained in:
committed by
jeffrey-signal
parent
1661f3b5f7
commit
5941ff814d
@@ -3557,38 +3557,41 @@ class AttachmentTable(
|
||||
)
|
||||
.readToSingleLong(0)
|
||||
|
||||
val archiveStatusMediaNameCounts: Map<ArchiveTransferState, Long> = ArchiveTransferState.entries.associateWith { state ->
|
||||
val archiveStatusMediaNameCounts: Map<ArchiveTransferState, Long> = ArchiveTransferState.entries.associateWith { 0L }.toMutableMap().apply {
|
||||
readableDatabase.query(
|
||||
"""
|
||||
SELECT COUNT(*) FROM (
|
||||
SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY
|
||||
SELECT $ARCHIVE_TRANSFER_STATE, COUNT(*) FROM (
|
||||
SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY, $ARCHIVE_TRANSFER_STATE
|
||||
FROM $TABLE_NAME LEFT JOIN ${MessageTable.TABLE_NAME} ON $TABLE_NAME.$MESSAGE_ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
WHERE ${buildAttachmentsThatCanArchiveQuery(archiveTransferStateFilter = "$ARCHIVE_TRANSFER_STATE = ${state.value}")}
|
||||
)
|
||||
WHERE ${buildAttachmentsThatCanArchiveQuery(archiveTransferStateFilter = "1=1")}
|
||||
) GROUP BY $ARCHIVE_TRANSFER_STATE
|
||||
"""
|
||||
)
|
||||
.readToSingleLong(0)
|
||||
).forEach { cursor ->
|
||||
this[ArchiveTransferState.deserialize(cursor.getInt(0))] = cursor.getLong(1)
|
||||
}
|
||||
}
|
||||
|
||||
val uniqueEligibleMediaNamesWithThumbnailsCount =
|
||||
readableDatabase.query("SELECT COUNT(*) FROM (SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY FROM $TABLE_NAME WHERE $DATA_HASH_END NOT NULL AND $REMOTE_KEY NOT NULL AND $THUMBNAIL_FILE NOT NULL AND $QUOTE = 0 AND $MESSAGE_ID != $WALLPAPER_MESSAGE_ID)")
|
||||
.readToSingleLong(-1L)
|
||||
val archiveStatusMediaNameThumbnailCounts: Map<ArchiveTransferState, Long> = ArchiveTransferState.entries.associateWith { state ->
|
||||
|
||||
val archiveStatusMediaNameThumbnailCounts: Map<ArchiveTransferState, Long> = ArchiveTransferState.entries.associateWith { 0L }.toMutableMap().apply {
|
||||
readableDatabase.query(
|
||||
"""
|
||||
SELECT COUNT(*) FROM (
|
||||
SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY
|
||||
SELECT $ARCHIVE_THUMBNAIL_TRANSFER_STATE, COUNT(*) FROM (
|
||||
SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY, $ARCHIVE_THUMBNAIL_TRANSFER_STATE
|
||||
FROM $TABLE_NAME LEFT JOIN ${MessageTable.TABLE_NAME} ON $TABLE_NAME.$MESSAGE_ID = ${MessageTable.TABLE_NAME}.${MessageTable.ID}
|
||||
WHERE
|
||||
${buildAttachmentsThatCanArchiveQuery("$ARCHIVE_THUMBNAIL_TRANSFER_STATE = ${state.value}")} AND
|
||||
WHERE
|
||||
${buildAttachmentsThatCanArchiveQuery("1=1")} AND
|
||||
$QUOTE = 0 AND
|
||||
($CONTENT_TYPE LIKE 'image/%' OR $CONTENT_TYPE LIKE 'video/%') AND
|
||||
$CONTENT_TYPE != 'image/svg+xml' AND
|
||||
$MESSAGE_ID != $WALLPAPER_MESSAGE_ID
|
||||
)
|
||||
) GROUP BY $ARCHIVE_THUMBNAIL_TRANSFER_STATE
|
||||
"""
|
||||
)
|
||||
.readToSingleLong(0)
|
||||
).forEach { cursor ->
|
||||
this[ArchiveTransferState.deserialize(cursor.getInt(0))] = cursor.getLong(1)
|
||||
}
|
||||
}
|
||||
|
||||
val pendingAttachmentUploadBytes = getPendingArchiveUploadBytes()
|
||||
@@ -3599,9 +3602,9 @@ class AttachmentTable(
|
||||
FROM (
|
||||
SELECT DISTINCT $DATA_HASH_END, $REMOTE_KEY, $DATA_SIZE
|
||||
FROM $TABLE_NAME
|
||||
WHERE
|
||||
$DATA_FILE NOT NULL AND
|
||||
$DATA_HASH_END NOT NULL AND
|
||||
WHERE
|
||||
$DATA_FILE NOT NULL AND
|
||||
$DATA_HASH_END NOT NULL AND
|
||||
$REMOTE_KEY NOT NULL AND
|
||||
$ARCHIVE_TRANSFER_STATE = ${ArchiveTransferState.FINISHED.value}
|
||||
)
|
||||
|
||||
@@ -33,6 +33,11 @@ final class LogSectionBadges implements LogSection {
|
||||
InAppPaymentTable.InAppPayment latestRecurringDonation = SignalDatabase.inAppPayments().getLatestInAppPaymentByType(InAppPaymentType.RECURRING_DONATION);
|
||||
|
||||
if (latestRecurringDonation != null) {
|
||||
InAppPaymentSubscriberRecord donationSubscriber = InAppPaymentsRepository.getSubscriber(InAppPaymentSubscriberRecord.Type.DONATION);
|
||||
boolean shouldCancel = donationSubscriber != null
|
||||
? donationSubscriber.getRequiresCancel()
|
||||
: SignalStore.inAppPayments().getShouldCancelSubscriptionBeforeNextSubscribeAttempt();
|
||||
|
||||
return new StringBuilder().append("Badge Count : ").append(Recipient.self().getBadges().size()).append("\n")
|
||||
.append("ExpiredBadge : ").append(SignalStore.inAppPayments().getExpiredBadge() != null).append("\n")
|
||||
.append("LastKeepAliveLaunchTime : ").append(SignalStore.inAppPayments().getLastKeepAliveLaunchTime()).append("\n")
|
||||
@@ -44,7 +49,7 @@ final class LogSectionBadges implements LogSection {
|
||||
.append("InAppPaymentData.Error : ").append(getError(latestRecurringDonation.getData())).append("\n")
|
||||
.append("InAppPaymentData.Cancellation : ").append(getCancellation(latestRecurringDonation.getData())).append("\n")
|
||||
.append("DisplayBadgesOnProfile : ").append(SignalStore.inAppPayments().getDisplayBadgesOnProfile()).append("\n")
|
||||
.append("ShouldCancelBeforeNextAttempt : ").append(InAppPaymentsRepository.getShouldCancelSubscriptionBeforeNextSubscribeAttempt(InAppPaymentSubscriberRecord.Type.DONATION)).append("\n")
|
||||
.append("ShouldCancelBeforeNextAttempt : ").append(shouldCancel).append("\n")
|
||||
.append("IsUserManuallyCancelledDonation : ").append(SignalStore.inAppPayments().isDonationSubscriptionManuallyCancelled()).append("\n");
|
||||
|
||||
} else {
|
||||
|
||||
@@ -105,7 +105,12 @@ class LogSectionRemoteBackups : LogSection {
|
||||
}
|
||||
|
||||
output.append("\n -- Attachment Stats\n")
|
||||
output.append(SignalDatabase.attachments.debugGetAttachmentStats().prettyString())
|
||||
val backupInProgress = SignalStore.backup.archiveUploadState?.state?.let { it != ArchiveUploadProgressState.State.None && it != ArchiveUploadProgressState.State.UserCanceled } ?: false
|
||||
if (SignalStore.backup.hasBackupCreationError || backupInProgress) {
|
||||
output.append(SignalDatabase.attachments.debugGetAttachmentStats().prettyString())
|
||||
} else {
|
||||
output.append("Skipped (last backup succeeded and no upload in progress)\n")
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
@@ -354,6 +354,16 @@ public class SubmitDebugLogActivity extends BaseActivity {
|
||||
private void initViewModel() {
|
||||
viewModel.getMode().observe(this, this::presentMode);
|
||||
viewModel.getEvents().observe(this, this::presentEvents);
|
||||
viewModel.getSlowPrefixWarning().observe(this, this::presentSlowPrefixWarning);
|
||||
}
|
||||
|
||||
private void presentSlowPrefixWarning(@NonNull Long durationMillis) {
|
||||
int durationSeconds = (int) Math.round(durationMillis / 1000.0);
|
||||
new MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.SubmitDebugLogActivity_slow_log_title)
|
||||
.setMessage(getString(R.string.SubmitDebugLogActivity_slow_log_message, durationSeconds))
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private void subscribeToLogLines() {
|
||||
|
||||
+17
-7
@@ -373,18 +373,28 @@ public class SubmitDebugLogRepository {
|
||||
|
||||
int maxTitleLength = SECTIONS.stream().reduce(0, (max, section) -> Math.max(max, section.getTitle().length()), Integer::sum);
|
||||
|
||||
List<LogLine> allLines = new ArrayList<>();
|
||||
|
||||
List<Future<List<LogLine>>> futures = new ArrayList<>(SECTIONS.size());
|
||||
for (LogSection section : SECTIONS) {
|
||||
List<LogLine> lines = getLinesForSection(context, section, maxTitleLength);
|
||||
futures.add(SignalExecutors.BOUNDED.submit(() -> getLinesForSection(context, section, maxTitleLength)));
|
||||
}
|
||||
|
||||
if (SECTIONS.indexOf(section) != SECTIONS.size() - 1) {
|
||||
for (int i = 0; i < SECTION_SPACING; i++) {
|
||||
lines.add(SimpleLogLine.EMPTY);
|
||||
}
|
||||
List<LogLine> allLines = new ArrayList<>();
|
||||
for (int i = 0; i < futures.size(); i++) {
|
||||
List<LogLine> lines;
|
||||
try {
|
||||
lines = futures.get(i).get();
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
Log.w(TAG, "Failed to read section " + SECTIONS.get(i).getTitle(), e);
|
||||
lines = new ArrayList<>();
|
||||
}
|
||||
|
||||
allLines.addAll(lines);
|
||||
|
||||
if (i != futures.size() - 1) {
|
||||
for (int j = 0; j < SECTION_SPACING; j++) {
|
||||
allLines.add(SimpleLogLine.EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<LogLine> withIds = new ArrayList<>(allLines.size());
|
||||
|
||||
+20
-6
@@ -15,6 +15,7 @@ import org.signal.core.util.tracing.Tracer;
|
||||
import org.signal.debuglogsviewer.DebugLogsViewer;
|
||||
import org.thoughtcrime.securesms.database.LogDatabase;
|
||||
import org.thoughtcrime.securesms.dependencies.AppDependencies;
|
||||
import org.thoughtcrime.securesms.util.RemoteConfig;
|
||||
import org.thoughtcrime.securesms.util.SingleLiveEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -28,20 +29,23 @@ public class SubmitDebugLogViewModel extends ViewModel {
|
||||
|
||||
private static final String TAG = Log.tag(SubmitDebugLogViewModel.class);
|
||||
|
||||
private static final int CHUNK_SIZE = 10_000;
|
||||
private static final int CHUNK_SIZE = 10_000;
|
||||
private static final long SLOW_PREFIX_THRESHOLD_MILLIS = 3_000L;
|
||||
|
||||
private final SubmitDebugLogRepository repo;
|
||||
private final MutableLiveData<Mode> mode;
|
||||
private final SingleLiveEvent<Event> event;
|
||||
private final SingleLiveEvent<Long> slowPrefixWarning;
|
||||
private final long firstViewTime;
|
||||
private final byte[] trace;
|
||||
|
||||
private SubmitDebugLogViewModel() {
|
||||
this.repo = new SubmitDebugLogRepository();
|
||||
this.mode = new MutableLiveData<>();
|
||||
this.trace = Tracer.getInstance().serialize();
|
||||
this.firstViewTime = System.currentTimeMillis();
|
||||
this.event = new SingleLiveEvent<>();
|
||||
this.repo = new SubmitDebugLogRepository();
|
||||
this.mode = new MutableLiveData<>();
|
||||
this.trace = Tracer.getInstance().serialize();
|
||||
this.firstViewTime = System.currentTimeMillis();
|
||||
this.event = new SingleLiveEvent<>();
|
||||
this.slowPrefixWarning = new SingleLiveEvent<>();
|
||||
}
|
||||
|
||||
@NonNull Observable<List<String>> getLogLinesObservable() {
|
||||
@@ -50,7 +54,13 @@ public class SubmitDebugLogViewModel extends ViewModel {
|
||||
try {
|
||||
mode.postValue(Mode.LOADING);
|
||||
|
||||
long prefixStartTime = System.currentTimeMillis();
|
||||
repo.getPrefixLogLines(prefixLines -> {
|
||||
long prefixDurationMillis = System.currentTimeMillis() - prefixStartTime;
|
||||
if (prefixDurationMillis > SLOW_PREFIX_THRESHOLD_MILLIS && RemoteConfig.showSlowDebugLogWarning()) {
|
||||
slowPrefixWarning.postValue(prefixDurationMillis);
|
||||
}
|
||||
|
||||
try {
|
||||
List<String> prefixStrings = new ArrayList<>();
|
||||
for (LogLine line : prefixLines) {
|
||||
@@ -142,6 +152,10 @@ public class SubmitDebugLogViewModel extends ViewModel {
|
||||
return event;
|
||||
}
|
||||
|
||||
@NonNull LiveData<Long> getSlowPrefixWarning() {
|
||||
return slowPrefixWarning;
|
||||
}
|
||||
|
||||
void onDiskSaveLocationReady(@Nullable Uri uri) {
|
||||
if (uri == null) {
|
||||
Log.w(TAG, "Null URI!");
|
||||
|
||||
@@ -674,6 +674,15 @@ object RemoteConfig {
|
||||
hotSwappable = true
|
||||
)
|
||||
|
||||
/** Whether to surface a warning dialog when debug log prefix generation exceeds a threshold. */
|
||||
@JvmStatic
|
||||
@get:JvmName("showSlowDebugLogWarning")
|
||||
val showSlowDebugLogWarning: Boolean by remoteBoolean(
|
||||
key = "android.showSlowDebugLogWarning",
|
||||
defaultValue = false,
|
||||
hotSwappable = true
|
||||
)
|
||||
|
||||
/** How often we allow an automatic session reset. */
|
||||
@JvmStatic
|
||||
@get:JvmName("automaticSessionResetIntervalSeconds")
|
||||
|
||||
@@ -3114,6 +3114,10 @@
|
||||
<string name="SubmitDebugLogActivity_info" translatable="false">Info</string>
|
||||
<string name="SubmitDebugLogActivity_warning" translatable="false">Warn</string>
|
||||
<string name="SubmitDebugLogActivity_error" translatable="false">Error</string>
|
||||
<!-- Title of dialog shown when debug log prefix generation is unusually slow -->
|
||||
<string name="SubmitDebugLogActivity_slow_log_title" translatable="false">Slow log generation</string>
|
||||
<!-- Body of dialog shown when debug log prefix generation is unusually slow. %1$d is duration in seconds. -->
|
||||
<string name="SubmitDebugLogActivity_slow_log_message" translatable="false">Generating the debug log header took %1$d seconds. We should figure out what\'s slowing things down.</string>
|
||||
|
||||
<!-- SupportEmailUtil -->
|
||||
<string name="SupportEmailUtil_support_email" translatable="false">support@signal.org</string>
|
||||
|
||||
Reference in New Issue
Block a user