feat: add multi-source capture association
This commit is contained in:
parent
c8fb2e4094
commit
e6e7271094
4 changed files with 130 additions and 0 deletions
|
|
@ -11,6 +11,12 @@ d'image logique. Une sélection courante optionnelle référence exactement une
|
||||||
image déjà associée au Capture et ne modifie jamais cette image, son asset, ni
|
image déjà associée au Capture et ne modifie jamais cette image, son asset, ni
|
||||||
les résultats scientifiques existants.
|
les résultats scientifiques existants.
|
||||||
|
|
||||||
|
L'association explicite d'un asset `SOURCE` existant à un Capture existant est
|
||||||
|
idempotente : si cette même association existe déjà avec le rôle `SOURCE`, elle
|
||||||
|
est acceptée sans nouvelle ligne ni migration de schéma. Elle ne crée aucune
|
||||||
|
image logique, ne modifie aucune sélection et ne réalise aucun appariement
|
||||||
|
automatique.
|
||||||
|
|
||||||
`asset_derivations` est volontairement limité à un parent asset et un enfant
|
`asset_derivations` est volontairement limité à un parent asset et un enfant
|
||||||
asset, avec kind/version et fingerprint canonique de 32 octets. Il n'est pas un
|
asset, avec kind/version et fingerprint canonique de 32 octets. Il n'est pas un
|
||||||
DAG générique et ne réalise aucun développement RAW ni extraction vidéo. La
|
DAG générique et ne réalise aucun développement RAW ni extraction vidéo. La
|
||||||
|
|
|
||||||
|
|
@ -533,6 +533,8 @@ Lardon3DProjectDbResult lardon3d_project_db_list_captures(
|
||||||
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_asset(
|
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_asset(
|
||||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id,
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id,
|
||||||
Lardon3DProjectDbCaptureAssetRole role);
|
Lardon3DProjectDbCaptureAssetRole role);
|
||||||
|
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_source_asset(
|
||||||
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id);
|
||||||
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
||||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
||||||
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count);
|
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count);
|
||||||
|
|
|
||||||
|
|
@ -3191,6 +3191,28 @@ Lardon3DProjectDbResult lardon3d_project_db_attach_capture_asset(
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Lardon3DProjectDbResult lardon3d_project_db_attach_capture_source_asset(
|
||||||
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t asset_id) {
|
||||||
|
Lardon3DProjectDbResult result = lardon3d_project_db_attach_capture_asset(
|
||||||
|
database, capture_id, asset_id, LARDON3D_DB_CAPTURE_ASSET_SOURCE);
|
||||||
|
if (result != LARDON3D_PROJECT_DB_CONSTRAINT) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Lardon3DProjectDbCaptureAsset existing;
|
||||||
|
size_t count = 0;
|
||||||
|
result = lardon3d_project_db_list_capture_assets(database, capture_id, asset_id - 1,
|
||||||
|
&existing, 1, &count);
|
||||||
|
if (result != LARDON3D_PROJECT_DB_OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if (count == 1 && existing.asset_id == asset_id &&
|
||||||
|
existing.role == LARDON3D_DB_CAPTURE_ASSET_SOURCE) {
|
||||||
|
return LARDON3D_PROJECT_DB_OK;
|
||||||
|
}
|
||||||
|
return LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||||
|
}
|
||||||
|
|
||||||
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
Lardon3DProjectDbResult lardon3d_project_db_list_capture_assets(
|
||||||
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
Lardon3DProjectDb *database, uint64_t capture_id, uint64_t after_asset_id,
|
||||||
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count) {
|
Lardon3DProjectDbCaptureAsset *assets, size_t capacity, size_t *count) {
|
||||||
|
|
|
||||||
|
|
@ -105,6 +105,13 @@ typedef struct {
|
||||||
uint64_t image_id;
|
uint64_t image_id;
|
||||||
} ImportThread;
|
} ImportThread;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Lardon3DProjectDb *database;
|
||||||
|
uint64_t capture_id;
|
||||||
|
uint64_t asset_id;
|
||||||
|
Lardon3DProjectDbResult result;
|
||||||
|
} AttachSourceThread;
|
||||||
|
|
||||||
static void *
|
static void *
|
||||||
import_thread(void *userdata)
|
import_thread(void *userdata)
|
||||||
{
|
{
|
||||||
|
|
@ -117,6 +124,15 @@ import_thread(void *userdata)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
attach_source_thread(void *userdata)
|
||||||
|
{
|
||||||
|
AttachSourceThread *thread = userdata;
|
||||||
|
thread->result = lardon3d_project_db_attach_capture_source_asset(thread->database,
|
||||||
|
thread->capture_id, thread->asset_id);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
has_initial_capture(Lardon3DProjectDb *database, const Lardon3DProjectDbImage *image,
|
has_initial_capture(Lardon3DProjectDb *database, const Lardon3DProjectDbImage *image,
|
||||||
const Lardon3DProjectDbImageAsset *asset, uint64_t scanset_id,
|
const Lardon3DProjectDbImageAsset *asset, uint64_t scanset_id,
|
||||||
|
|
@ -271,6 +287,90 @@ run_test(void)
|
||||||
&& contexts[0].result == LARDON3D_IMAGE_CATALOG_ALREADY_PRESENT))
|
&& contexts[0].result == LARDON3D_IMAGE_CATALOG_ALREADY_PRESENT))
|
||||||
&& contexts[0].image_id == contexts[1].image_id);
|
&& contexts[0].image_id == contexts[1].image_id);
|
||||||
|
|
||||||
|
/* S3-C: explicit, idempotent SOURCE association does not mutate catalog policy. */
|
||||||
|
Lardon3DProjectDbImage concurrent_image;
|
||||||
|
Lardon3DProjectDbImageAsset concurrent_asset;
|
||||||
|
CHECK(lardon3d_project_db_load_image(database, contexts[0].image_id,
|
||||||
|
&concurrent_image, &concurrent_asset) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
uint64_t image_count_a_before = 0, image_count_b_before = 0;
|
||||||
|
CHECK(lardon3d_project_db_count_images(database, a.scanset_id,
|
||||||
|
&image_count_a_before) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_count_images(database, b.scanset_id,
|
||||||
|
&image_count_b_before) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
uint64_t selection_before = 0;
|
||||||
|
CHECK(lardon3d_project_db_get_selected_capture_image(database, capture_a.capture_id,
|
||||||
|
&selection_before) == LARDON3D_PROJECT_DB_OK
|
||||||
|
&& selection_before == image_a.image_id);
|
||||||
|
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database, capture_a.capture_id,
|
||||||
|
different_asset.asset_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database, capture_a.capture_id,
|
||||||
|
different_asset.asset_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database, capture_a.capture_id,
|
||||||
|
concurrent_asset.asset_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
Lardon3DProjectDbCaptureAsset source_page[4];
|
||||||
|
size_t source_count = 0;
|
||||||
|
CHECK(lardon3d_project_db_list_capture_assets(database, capture_a.capture_id, 0,
|
||||||
|
source_page, 4, &source_count) == LARDON3D_PROJECT_DB_OK && source_count == 3);
|
||||||
|
for (size_t index = 0; index < source_count; ++index) {
|
||||||
|
CHECK(source_page[index].capture_id == capture_a.capture_id
|
||||||
|
&& source_page[index].role == LARDON3D_DB_CAPTURE_ASSET_SOURCE
|
||||||
|
&& (index == 0 || source_page[index - 1].asset_id < source_page[index].asset_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
AttachSourceThread attach_contexts[2] = {
|
||||||
|
{.database = database, .capture_id = preexisting_capture.capture_id,
|
||||||
|
.asset_id = asset_a.asset_id},
|
||||||
|
{.database = database, .capture_id = preexisting_capture.capture_id,
|
||||||
|
.asset_id = asset_a.asset_id},
|
||||||
|
};
|
||||||
|
pthread_t attach_threads[2];
|
||||||
|
CHECK(pthread_create(&attach_threads[0], NULL, attach_source_thread,
|
||||||
|
&attach_contexts[0]) == 0);
|
||||||
|
CHECK(pthread_create(&attach_threads[1], NULL, attach_source_thread,
|
||||||
|
&attach_contexts[1]) == 0);
|
||||||
|
CHECK(pthread_join(attach_threads[0], NULL) == 0
|
||||||
|
&& pthread_join(attach_threads[1], NULL) == 0
|
||||||
|
&& attach_contexts[0].result == LARDON3D_PROJECT_DB_OK
|
||||||
|
&& attach_contexts[1].result == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database, capture_b.capture_id,
|
||||||
|
asset_a.asset_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
Lardon3DProjectDbCapture conflict_capture;
|
||||||
|
CHECK(lardon3d_project_db_create_capture(database, a.scanset_id, 2,
|
||||||
|
&conflict_capture) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_asset(database, conflict_capture.capture_id,
|
||||||
|
concurrent_asset.asset_id, LARDON3D_DB_CAPTURE_ASSET_DERIVED)
|
||||||
|
== LARDON3D_PROJECT_DB_OK);
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database,
|
||||||
|
conflict_capture.capture_id, concurrent_asset.asset_id)
|
||||||
|
== LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||||
|
size_t conflict_count = 0;
|
||||||
|
CHECK(lardon3d_project_db_list_capture_assets(database, conflict_capture.capture_id, 0,
|
||||||
|
source_page, 1, &conflict_count) == LARDON3D_PROJECT_DB_OK
|
||||||
|
&& conflict_count == 1
|
||||||
|
&& source_page[0].role == LARDON3D_DB_CAPTURE_ASSET_DERIVED);
|
||||||
|
|
||||||
|
lardon3d_project_db_close(database);
|
||||||
|
database = NULL;
|
||||||
|
state.project_db = NULL;
|
||||||
|
CHECK(lardon3d_project_db_open(database_path, &database, error)
|
||||||
|
== LARDON3D_PROJECT_DB_OK);
|
||||||
|
state.project_db = database;
|
||||||
|
CHECK(lardon3d_project_db_attach_capture_source_asset(database, capture_a.capture_id,
|
||||||
|
different_asset.asset_id) == LARDON3D_PROJECT_DB_OK);
|
||||||
|
source_count = 0;
|
||||||
|
CHECK(lardon3d_project_db_list_capture_assets(database, capture_a.capture_id, 0,
|
||||||
|
source_page, 4, &source_count) == LARDON3D_PROJECT_DB_OK && source_count == 3);
|
||||||
|
uint64_t selection_after = 0, image_count_a_after = 0, image_count_b_after = 0;
|
||||||
|
CHECK(lardon3d_project_db_get_selected_capture_image(database, capture_a.capture_id,
|
||||||
|
&selection_after) == LARDON3D_PROJECT_DB_OK && selection_after == selection_before);
|
||||||
|
CHECK(lardon3d_project_db_count_images(database, a.scanset_id,
|
||||||
|
&image_count_a_after) == LARDON3D_PROJECT_DB_OK
|
||||||
|
&& image_count_a_after == image_count_a_before);
|
||||||
|
CHECK(lardon3d_project_db_count_images(database, b.scanset_id,
|
||||||
|
&image_count_b_after) == LARDON3D_PROJECT_DB_OK
|
||||||
|
&& image_count_b_after == image_count_b_before);
|
||||||
|
|
||||||
char bulk_directory[PATH_MAX];
|
char bulk_directory[PATH_MAX];
|
||||||
CHECK(join_path(bulk_directory, root, "bulk") && mkdir(bulk_directory, 0700) == 0);
|
CHECK(join_path(bulk_directory, root, "bulk") && mkdir(bulk_directory, 0700) == 0);
|
||||||
for (uint64_t index = 1; index <= 2048; ++index) {
|
for (uint64_t index = 1; index <= 2048; ++index) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue