Files
immich/mobile-v2/test/benchmark_insert_test.dart
2025-02-26 19:44:33 +05:30

233 lines
5.9 KiB
Dart

import 'dart:io';
import 'package:collection/collection.dart';
// ignore: import_rule_drift
import 'package:drift/drift.dart';
// ignore: import_rule_drift
import 'package:drift/native.dart';
import 'package:faker/faker.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:immich_mobile/domain/models/asset.model.dart';
import 'package:immich_mobile/domain/repositories/asset.repository.dart';
import 'package:immich_mobile/domain/repositories/asset_isar.repository.dart';
import 'package:immich_mobile/domain/repositories/database.repository.dart';
import 'package:isar/isar.dart';
// import 'package:isar/isar.dart';
import 'package:sqlite3/sqlite3.dart';
import 'test_utils.dart';
List<Asset> _generateAssets(int count) {
final assets = <Asset>[];
final faker = Faker();
for (int i = 0; i < count; i++) {
assets.add(Asset(
id: i,
name: 'Asset $i',
hash: faker.guid.guid(),
height: faker.randomGenerator.integer(1000),
width: faker.randomGenerator.integer(1000),
type: faker.randomGenerator.element(AssetType.values),
createdTime: faker.date.dateTime(),
modifiedTime: faker.date.dateTime(),
duration: faker.randomGenerator.integer(100),
localId: faker.guid.guid(),
remoteId: faker.guid.guid(),
livePhotoVideoId: faker.guid.guid(),
));
}
return assets;
}
Future<void> _benchDriftInsertsBatched({
required String name,
required Iterable<List<Asset>> assets,
required DriftDatabaseRepository db,
}) async {
final repo = AssetRepository(db: db);
final sp = Stopwatch()..start();
for (final chunk in assets) {
await repo.upsertAll(chunk);
}
print('$name - ${sp.elapsed}');
}
Future<void> _benchIsarInsertsBatched({
required String name,
required Iterable<List<Asset>> assets,
required Isar db,
}) async {
final repo = AssetIsarRepository(db: db);
final sp = Stopwatch()..start();
for (final chunk in assets) {
await repo.upsertAll(chunk);
}
print('$name - ${sp.elapsed}');
}
Future<void> _benchDriftInsertsNonBatched({
required String name,
required List<Asset> assets,
required DriftDatabaseRepository db,
}) async {
final repo = AssetRepository(db: db);
final sp = Stopwatch()..start();
for (final chunk in assets) {
await repo.upsert(chunk);
}
print('$name - ${sp.elapsed}');
}
Future<void> _benchIsarInsertsNonBatched({
required String name,
required List<Asset> assets,
required Isar db,
}) async {
final repo = AssetIsarRepository(db: db);
final sp = Stopwatch()..start();
for (final chunk in assets) {
await repo.upsert(chunk);
}
print('$name - ${sp.elapsed}');
}
Future<void> _cleanup(File file) async {
if (await file.exists()) {
await file.delete();
}
}
void main() {
late DriftDatabaseRepository drift;
late Isar isar;
// ignore: avoid-local-functions
Future<void> setup() async {
drift = DriftDatabaseRepository(LazyDatabase(() {
sqlite3.tempDirectory = 'test/';
return NativeDatabase.createInBackground(File('test/test.sqlite'));
}));
isar = await TestUtils.initIsar();
}
// ignore: avoid-local-functions
Future<void> cleanupFiles() async {
await _cleanup(File('test/test.sqlite'));
await _cleanup(File('test/test.sqlite-shm'));
await _cleanup(File('test/test.sqlite-wal'));
await _cleanup(File('test/default.isar'));
}
// ignore: avoid-local-functions
Future<void> closeDb() async {
await drift.close();
if (isar.isOpen) {
await isar.close();
}
}
test('10K assets', () async {
await cleanupFiles();
await setup();
final assets = _generateAssets(10000);
await _benchDriftInsertsBatched(
name: 'Drift 10K assets batched - 1K slice',
assets: assets.slices(1000),
db: drift,
);
await _benchIsarInsertsBatched(
name: 'Isar 10K assets batched - 1K slice',
assets: assets.slices(1000),
db: isar,
);
await closeDb();
await cleanupFiles();
await setup();
await _benchDriftInsertsNonBatched(
name: 'Drift 10K assets non-batched',
assets: assets,
db: drift,
);
await _benchIsarInsertsNonBatched(
name: 'Isar 10K assets non-batched',
assets: assets,
db: isar,
);
});
test(
'100K assets',
() async {
await cleanupFiles();
await setup();
final assets = _generateAssets(100000);
await _benchDriftInsertsBatched(
name: 'Drift 100K assets batched - 10K slice',
assets: assets.slices(10000),
db: drift,
);
await _benchIsarInsertsBatched(
name: 'Isar 100K assets batched - 10K slice',
assets: assets.slices(10000),
db: isar,
);
await closeDb();
await cleanupFiles();
await setup();
await _benchDriftInsertsNonBatched(
name: 'Drift 100K assets non-batched',
assets: assets,
db: drift,
);
await _benchIsarInsertsNonBatched(
name: 'Isar 100K assets non-batched',
assets: assets,
db: isar,
);
},
timeout: Timeout(Duration(minutes: 5)),
);
test(
'1M assets',
() async {
await cleanupFiles();
await setup();
final assets = _generateAssets(1000000);
await _benchDriftInsertsBatched(
name: 'Drift 1M assets batched - 10K slice',
assets: assets.slices(10000),
db: drift,
);
await _benchIsarInsertsBatched(
name: 'Isar 1M assets batched - 10K slice',
assets: assets.slices(10000),
db: isar,
);
await closeDb();
await cleanupFiles();
await setup();
await _benchDriftInsertsNonBatched(
name: 'Drift 1M assets non-batched',
assets: assets,
db: drift,
);
await _benchIsarInsertsNonBatched(
name: 'Isar 1M assets non-batched',
assets: assets,
db: isar,
);
},
timeout: Timeout(Duration(minutes: 25)),
);
}