mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-23 10:20:25 +01:00
Add measurements, improve MSL insert.
This commit is contained in:
@@ -178,12 +178,18 @@ public final class SignalLocalMetrics {
|
||||
public static final class GroupMessageSend {
|
||||
private static final String NAME = "group-message-send";
|
||||
|
||||
private static final String SPLIT_DB_INSERT = "db-insert";
|
||||
private static final String SPLIT_JOB_ENQUEUE = "job-enqueue";
|
||||
private static final String SPLIT_JOB_PRE_NETWORK = "job-pre-network";
|
||||
private static final String SPLIT_NETWORK = "network";
|
||||
private static final String SPLIT_JOB_POST_NETWORK = "job-post-network";
|
||||
private static final String SPLIT_UI_UPDATE = "ui-update";
|
||||
private static final String SPLIT_DB_INSERT = "db-insert";
|
||||
private static final String SPLIT_JOB_ENQUEUE = "job-enqueue";
|
||||
private static final String SPLIT_JOB_PRE_NETWORK = "job-pre-network";
|
||||
private static final String SPLIT_SENDER_KEY_SHARED = "sk-shared";
|
||||
private static final String SPLIT_ENCRYPTION = "encryption";
|
||||
private static final String SPLIT_NETWORK_SENDER_KEY = "network-sk";
|
||||
private static final String SPLIT_NETWORK_SENDER_KEY_SYNC = "network-sk-sync";
|
||||
private static final String SPLIT_MSL_SENDER_KEY = "msl-sk";
|
||||
private static final String SPLIT_NETWORK_LEGACY = "network-legacy";
|
||||
private static final String SPLIT_NETWORK_LEGACY_SYNC = "network-legacy-sync";
|
||||
private static final String SPLIT_JOB_POST_NETWORK = "job-post-network";
|
||||
private static final String SPLIT_UI_UPDATE = "ui-update";
|
||||
|
||||
private static final Map<Long, String> ID_MAP = new HashMap<>();
|
||||
|
||||
@@ -205,14 +211,44 @@ public final class SignalLocalMetrics {
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_JOB_ENQUEUE);
|
||||
}
|
||||
|
||||
public static void onNetworkStarted(long messageId) {
|
||||
public static void onSenderKeyStarted(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_JOB_PRE_NETWORK);
|
||||
}
|
||||
|
||||
public static void onNetworkFinished(long messageId) {
|
||||
public static void onSenderKeyShared(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK);
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_SENDER_KEY_SHARED);
|
||||
}
|
||||
|
||||
public static void onSenderKeyEncrypted(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_ENCRYPTION);
|
||||
}
|
||||
|
||||
public static void onSenderKeyMessageSent(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_SENDER_KEY);
|
||||
}
|
||||
|
||||
public static void onSenderKeySyncSent(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_SENDER_KEY_SYNC);
|
||||
}
|
||||
|
||||
public static void onSenderKeyMslInserted(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_MSL_SENDER_KEY);
|
||||
}
|
||||
|
||||
public static void onLegacyMessageSent(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_LEGACY);
|
||||
}
|
||||
|
||||
public static void onLegacySyncFinished(long messageId) {
|
||||
if (!ID_MAP.containsKey(messageId)) return;
|
||||
LocalMetrics.getInstance().split(requireId(messageId), SPLIT_NETWORK_LEGACY_SYNC);
|
||||
}
|
||||
|
||||
public static void onJobFinished(long messageId) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
@@ -19,9 +20,13 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class SqlUtil {
|
||||
|
||||
/** The maximum number of arguments (i.e. question marks) allowed in a SQL statement. */
|
||||
private static final int MAX_QUERY_ARGS = 999;
|
||||
|
||||
private SqlUtil() {}
|
||||
|
||||
public static boolean tableExists(@NonNull SQLiteDatabase db, @NonNull String table) {
|
||||
@@ -155,6 +160,41 @@ public final class SqlUtil {
|
||||
return new Query(column + " IN (" + query.toString() + ")", buildArgs(args));
|
||||
}
|
||||
|
||||
public static @NonNull List<Query> buildCustomCollectionQuery(@NonNull String query, @NonNull List<String[]> argList) {
|
||||
return buildCustomCollectionQuery(query, argList, MAX_QUERY_ARGS);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static @NonNull List<Query> buildCustomCollectionQuery(@NonNull String query, @NonNull List<String[]> argList, int maxQueryArgs) {
|
||||
int batchSize = maxQueryArgs / argList.get(0).length;
|
||||
|
||||
return Util.chunk(argList, batchSize)
|
||||
.stream()
|
||||
.map(argBatch -> buildSingleCustomCollectionQuery(query, argBatch))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static @NonNull Query buildSingleCustomCollectionQuery(@NonNull String query, @NonNull List<String[]> argList) {
|
||||
StringBuilder outputQuery = new StringBuilder();
|
||||
String[] outputArgs = new String[argList.get(0).length * argList.size()];
|
||||
int argPosition = 0;
|
||||
|
||||
for (int i = 0, len = argList.size(); i < len; i++) {
|
||||
outputQuery.append("(").append(query).append(")");
|
||||
if (i < len - 1) {
|
||||
outputQuery.append(" OR ");
|
||||
}
|
||||
|
||||
String[] args = argList.get(i);
|
||||
for (String arg : args) {
|
||||
outputArgs[argPosition] = arg;
|
||||
argPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
return new Query(outputQuery.toString(), outputArgs);
|
||||
}
|
||||
|
||||
public static @NonNull Query buildQuery(@NonNull String where, @NonNull Object... args) {
|
||||
return new SqlUtil.Query(where, SqlUtil.buildArgs(args));
|
||||
}
|
||||
@@ -168,6 +208,68 @@ public final class SqlUtil {
|
||||
return output;
|
||||
}
|
||||
|
||||
public static List<Query> buildBulkInsert(@NonNull String tableName, @NonNull String[] columns, List<ContentValues> contentValues) {
|
||||
return buildBulkInsert(tableName, columns, contentValues, MAX_QUERY_ARGS);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static List<Query> buildBulkInsert(@NonNull String tableName, @NonNull String[] columns, List<ContentValues> contentValues, int maxQueryArgs) {
|
||||
int batchSize = maxQueryArgs / columns.length;
|
||||
|
||||
return Util.chunk(contentValues, batchSize)
|
||||
.stream()
|
||||
.map(batch -> buildSingleBulkInsert(tableName, columns, batch))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static Query buildSingleBulkInsert(@NonNull String tableName, @NonNull String[] columns, List<ContentValues> contentValues) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("INSERT INTO ").append(tableName).append(" (");
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
builder.append(columns[i]);
|
||||
if (i < columns.length - 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
builder.append(") VALUES ");
|
||||
|
||||
StringBuilder placeholder = new StringBuilder();
|
||||
placeholder.append("(");
|
||||
|
||||
for (int i = 0; i < columns.length; i++) {
|
||||
placeholder.append("?");
|
||||
if (i < columns.length - 1) {
|
||||
placeholder.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
placeholder.append(")");
|
||||
|
||||
|
||||
for (int i = 0, len = contentValues.size(); i < len; i++) {
|
||||
builder.append(placeholder);
|
||||
if (i < len - 1) {
|
||||
builder.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
String query = builder.toString();
|
||||
String[] args = new String[columns.length * contentValues.size()];
|
||||
|
||||
int i = 0;
|
||||
for (ContentValues values : contentValues) {
|
||||
for (String column : columns) {
|
||||
Object value = values.get(column);
|
||||
args[i] = value != null ? values.get(column).toString() : "null";
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
return new Query(query, args);
|
||||
}
|
||||
|
||||
public static class Query {
|
||||
private final String where;
|
||||
private final String[] whereArgs;
|
||||
|
||||
Reference in New Issue
Block a user