secure commit
This commit is contained in:
parent
ba21f5eb83
commit
40d9d27ba6
20 changed files with 1290 additions and 103 deletions
15
README.md
15
README.md
|
|
@ -34,8 +34,12 @@ persistante, enrichissable et versionnable.
|
|||
- **Image View** : vues triées et filtrées pour la TUI
|
||||
- **Task** : moteur de tâches avec pause/reprise, annulation et séquences
|
||||
- **Task Checkpoint v1** : snapshot durable, fichier atomique et reprise sûre
|
||||
- **Project Database v19** : fondations v18 préservées, avec Capture / Asset
|
||||
Provenance additive
|
||||
- **Project Database v20** : fondations v19 préservées, avec persistance
|
||||
additive des tâches de campagne d'acquisition
|
||||
- **Exécution durable de campagne d'acquisition** : tâche générique à requête
|
||||
typée immuable, confirmations `CALLER_EXPLICIT`, curseur et correspondance
|
||||
tâche/groupe→Capture persistants ; un groupe S3-E par séquence, reprise par
|
||||
la registry, la Queue et le Resource Governor existants
|
||||
- **Sparse SfM Gates C/D/E** : géométrie calibrée, noyau incrémental et Bundle
|
||||
Adjustment final par composante, tous PASS / FROZEN
|
||||
- **Sparse SfM Gate F** : orchestration durable, runtime gouverné et publication
|
||||
|
|
@ -62,15 +66,14 @@ persistante, enrichissable et versionnable.
|
|||
|
||||
### Prochaine tranche
|
||||
|
||||
- **Exécution durable de campagne d'acquisition** : confirmations et progression
|
||||
persistantes, matérialisation S3-E incrémentale, reprise par `capture_id` retenu
|
||||
et admission par les Task/Scheduler/Governor existants. Voir la
|
||||
- **Intégration multi-campagne réelle A6000 + S21 Engine Bay** : exécuter les
|
||||
campagnes persistantes à travers le pipeline scientifique existant. Voir la
|
||||
[roadmap canonique](docs/roadmap/roadmap.md).
|
||||
|
||||
### Plus tard / différé
|
||||
|
||||
- publication durable dense/mesh et scratch SSD externe optionnel gouverné ;
|
||||
- workflow TUI de confirmation/progression et sources mixtes multi-ScanSet ;
|
||||
- workflow TUI de confirmation/progression ;
|
||||
- vidéo/keyframes et **Capture Guidance / Live Coverage** : analyse et viewer de
|
||||
couverture, suggestions de prises de vue puis assistance live, après
|
||||
reconstruction mature ;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Base de données projet Lardon3D
|
||||
|
||||
## Capture / Asset Provenance v1 — Project DB v19
|
||||
## Capture / Asset Provenance v1 — Project DB v19 (historique FROZEN)
|
||||
|
||||
**PASS / FROZEN.** La migration transactionnelle v18→v19
|
||||
ajoute seulement une fondation de catalogue : `captures`, `capture_images`,
|
||||
|
|
@ -109,10 +109,57 @@ confirmation explicite `CALLER_EXPLICIT` avant tout regroupement. Le fixture
|
|||
d'intégration couvre l'adaptateur, sa matérialisation et son retry ; aucune
|
||||
mutation de campagne complète n'a été effectuée.
|
||||
|
||||
Restent hors S3 : identité persistante de campagne ou de Task, exécution par
|
||||
scheduler/Governor, traitement de campagne complet, TUI, scrub d'assets et
|
||||
réconciliation des orphelins, ainsi que vidéo et reconstruction aval lorsqu'ils
|
||||
sont applicables.
|
||||
Restent hors S3 : TUI, scrub d'assets et réconciliation des orphelins, ainsi
|
||||
que vidéo et reconstruction aval lorsqu'ils sont applicables. L'identité
|
||||
opérationnelle persistante de campagne, son exécution par Task/Scheduler/Governor
|
||||
et sa reprise sont définies par Project DB v20 ci-dessous ; ils ne modifient pas
|
||||
le contrat S3.
|
||||
|
||||
## Exécution durable de campagne d'acquisition — Project DB v20
|
||||
|
||||
**PASS / FROZEN.** La migration transactionnelle additive
|
||||
v19→v20 ajoute `acquisition_campaign_tasks` et
|
||||
`acquisition_campaign_captures`, sans modifier les tables ni les identités
|
||||
Capture/Asset de v19. Une base v19 est donc ouverte par la chaîne séquentielle
|
||||
existante ; un échec de migration laisse la v19 complète et utilisable.
|
||||
|
||||
`acquisition_campaign_tasks` est lié une-à-une à la tâche générique par
|
||||
`task_id`, qui est l'identité opérationnelle de la campagne. La création et les
|
||||
checkpoints enregistrent dans une même transaction le snapshot Task générique,
|
||||
sa référence de checkpoint et le record typé de campagne. Ce record conserve le
|
||||
`scanset_id`, le curseur `next_group_id`, le nombre de groupes et une requête
|
||||
immuable : un upsert ne peut faire progresser le curseur que si ScanSet, nombre
|
||||
de groupes et octets de requête sont identiques.
|
||||
|
||||
La requête v1 est un codec borné, déterministe, à magic/version explicites et
|
||||
champs entiers de largeur fixe little-endian. Elle sérialise les sources, leurs
|
||||
métadonnées déjà validées, les confirmations et les options d'ingestion ; elle
|
||||
est refusée si ses bornes, longueurs, énumérations, indices, plan ou octets de
|
||||
fin ne sont pas valides. Les confirmations sont ainsi persistées explicitement
|
||||
et ne confèrent que la basis `CALLER_EXPLICIT`, jamais une inférence `STRONG`.
|
||||
|
||||
Les groupes de plan gardent leurs IDs un-based. Pour chaque groupe achevé,
|
||||
`acquisition_campaign_captures` conserve la relation unique
|
||||
`(task_id, group_id) → capture_id` et interdit qu'un même Capture corresponde à
|
||||
deux groupes de la même tâche. Après le retour de S3-E, une transaction unique
|
||||
retient cette relation et avance `next_group_id`, avant la progression générique
|
||||
et le checkpoint. La reprise peut alors transmettre le `capture_id` retenu à
|
||||
S3-E, sans réhoming ni inférence depuis un chemin, SHA, basename, timestamp,
|
||||
métadonnée ou `image_id`.
|
||||
|
||||
Chaque séquence matérialise un seul groupe. Pause et annulation restent
|
||||
coopératives aux frontières de groupe ; après un groupe non terminal,
|
||||
`sequence_break` rend la réservation et force la réadmission par la Queue et le
|
||||
Resource Governor existants. À l'ouverture, la registry existante reconstruit
|
||||
la tâche depuis le Task ID et la requête durable, puis le mécanisme de reprise
|
||||
existant la soumet à la Queue. Cette tranche n'introduit aucun runtime, queue,
|
||||
governor, scheduler ou stockage parallèle et reste générique pour les sources
|
||||
mono-source comme multi-source.
|
||||
|
||||
La fenêtre résiduelle acceptée est strictement l'arrêt après le retour de S3-E
|
||||
et avant la transaction de rétention du Capture. Aucun `capture_id` n'est alors
|
||||
inféré et aucune garantie exactly-once ne lui est attribuée ; les autres
|
||||
frontières s'appuient sur la relation retenue et le curseur transactionnel.
|
||||
|
||||
### S3-D — Acquisition Pairing Evidence v1
|
||||
|
||||
|
|
@ -201,8 +248,10 @@ persistée exactement ; seule une composante de graphe non reconstruite est
|
|||
omise. Les comptes et métriques globaux décrivent exclusivement la géométrie
|
||||
effectivement persistée. Aucun placeholder ni table diagnostique n'est ajouté.
|
||||
|
||||
> Version courante : **v19**. La migration transactionnelle v18→v19 ajoute la
|
||||
> fondation Capture/Asset Provenance décrite ci-dessus sans modifier les tables
|
||||
> Version courante : **v20**. La migration transactionnelle additive v19→v20
|
||||
> ajoute les records de campagne durable décrits ci-dessus sans modifier les
|
||||
> tables ni identités Capture/Asset de v19. La migration transactionnelle
|
||||
> v18→v19 ajoute la fondation Capture/Asset Provenance sans modifier les tables
|
||||
> scientifiques historiques. La migration transactionnelle v17→v18 ajoute le
|
||||
> discriminateur générique nullable et les deux tables H minimales décrites
|
||||
> ci-dessus. La migration v16→v17 ajoute le
|
||||
|
|
@ -946,10 +995,17 @@ ouvert.
|
|||
|
||||
## Statut
|
||||
|
||||
**PASS / FROZEN** — SQLite système, schéma v19 et migrations séquentielles
|
||||
v1→v2→v3→v4→v5→v6→v7→v8→v9→v10→v11→v12→v13→v14→v15→v16→v17→v18→v19, identité projet, transactions
|
||||
**PASS / FROZEN** — SQLite système, schéma v20 et migrations séquentielles
|
||||
v1→v2→v3→v4→v5→v6→v7→v8→v9→v10→v11→v12→v13→v14→v15→v16→v17→v18→v19→v20, identité projet, transactions
|
||||
tâche+checkpoint, pagination de reprise et artefacts génériques.
|
||||
|
||||
**PASS / FROZEN** — Project DB v20 : migration additive
|
||||
v19→v20, record typé de campagne lié au Task ID, requête immuable bornée,
|
||||
confirmations `CALLER_EXPLICIT`, curseur et relation unique
|
||||
task/groupe→Capture. La reprise reste celle de la registry, de la Queue et du
|
||||
Resource Governor existants ; aucune identité de Capture n'est inférée dans la
|
||||
fenêtre résiduelle pré-rétention.
|
||||
|
||||
**IMPLEMENTED** — ouverture/fermeture avec le projet, identité INI/DB cohérente,
|
||||
publication de checkpoints par le projet et inventaire de reprise validé.
|
||||
|
||||
|
|
|
|||
|
|
@ -122,6 +122,15 @@ complet. Le scope GVR est persistant et immuable ; la reprise rejoue depuis le
|
|||
début avant publication et l'exact reuse Gate C absorbe un crash post-publication.
|
||||
Pause et annulation sont observées avant/after l'unité Gate B non préemptible.
|
||||
|
||||
**PASS / FROZEN** — `acquisition_campaign.run` v1 est une
|
||||
tâche durable reconstruite par la registry existante à partir de son Task ID et
|
||||
de sa requête typée immuable Project DB v20. Elle matérialise un seul groupe
|
||||
S3-E par séquence, vérifie pause/annulation aux frontières de groupe, retient
|
||||
transactionnellement Capture et curseur avant progression/checkpoint, puis
|
||||
appelle `sequence_break` avant le groupe suivant. Sa reprise passe par la Queue
|
||||
et le Resource Governor existants ; aucune boucle d'exécution parallèle n'est
|
||||
introduite.
|
||||
|
||||
Le chemin de production de l'import ne possède plus de thread ni de drapeau
|
||||
d'annulation privés. Son wrapper TUI ne fait qu'enqueue/cancel/observer la
|
||||
tâche générique. Chaque callback traite un lot borné, checkpoint hors mutex de
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ Le stem commun ne prouve jamais une acquisition. Les 953 propositions doivent
|
|||
être confirmées et deviennent `CALLER_EXPLICIT`, jamais `STRONG`. La campagne
|
||||
complète n'a pas encore été matérialisée.
|
||||
|
||||
### Limite de reprise DB v19
|
||||
### Limite de reprise DB v19 (historique)
|
||||
|
||||
S3-E reprend une matérialisation connue par `resume_capture_id`. Une campagne
|
||||
peut reconstruire son plan et conserver côté appelant le `capture_id` de chaque
|
||||
|
|
@ -85,31 +85,41 @@ future identité durable de requête/campagne pourra fermer cette fenêtre ; ell
|
|||
ne sera jamais déduite d'un chemin, SHA, basename, timestamp, métadonnée ou
|
||||
`image_id`.
|
||||
|
||||
## NEXT — exécution durable de campagne d'acquisition
|
||||
## Exécution durable de campagne d'acquisition — PASS / FROZEN
|
||||
|
||||
La prochaine tranche architecturale unique est l'exécution opérationnelle du
|
||||
plan S3 gelé en réutilisant Task, Scheduler et Governor existants :
|
||||
Project DB v20 apporte une migration additive v19→v20. Une tâche de campagne
|
||||
enregistre atomiquement son snapshot générique, sa référence de checkpoint et
|
||||
sa requête typée immuable. Le Task ID est l'identité opérationnelle de la
|
||||
campagne ; la requête ne déduit aucune identité depuis les sources. Son codec
|
||||
v1 est borné, à champs de largeur fixe et little-endian ; il conserve les
|
||||
sources, les confirmations explicites et les options d'ingestion.
|
||||
|
||||
1. identité durable de requête et payload Task borné ;
|
||||
2. persistance/rechargement des confirmations, du curseur et des `capture_id` ;
|
||||
3. matérialisation incrémentale d'un groupe S3-E par unité sûre ;
|
||||
4. checkpoint après rétention durable, pause/reprise/annulation aux frontières ;
|
||||
5. admission et budgets par l'unique Resource Governor ;
|
||||
6. progression et échecs sans runtime, queue ou persistence parallèle.
|
||||
La requête persiste les confirmations comme `CALLER_EXPLICIT`, jamais comme
|
||||
inférence `STRONG`. Le plan conserve des IDs de groupe un-based et Project DB
|
||||
persiste la correspondance `(task_id, group_id) → capture_id`, ainsi que le
|
||||
curseur. Chaque séquence admet et matérialise exactement un groupe via S3-E.
|
||||
Après le retour de S3-E, une transaction conserve le Capture et avance le
|
||||
curseur avant la progression générique et le checkpoint. Pause et annulation
|
||||
sont coopératives aux frontières de groupe ; entre deux groupes,
|
||||
`sequence_break` rend la réservation et impose une nouvelle admission.
|
||||
|
||||
Cette tranche décidera explicitement si une évolution additive après DB v19 est
|
||||
nécessaire. Elle ne peut ni changer les identités S3 ni fusionner des Captures.
|
||||
À la réouverture, la registry existante reconstruit la tâche à partir de son
|
||||
Task ID et de sa requête, puis la Queue et le Governor existants la réadmettent.
|
||||
Aucun runtime, queue, governor ou mécanisme de persistance parallèle n'est
|
||||
introduit. La fenêtre résiduelle acceptée demeure l'arrêt après le retour de
|
||||
S3-E et avant la transaction de rétention : elle ne déclenche aucune inférence
|
||||
de Capture et ne fournit pas de garantie exactly-once pour ce groupe.
|
||||
|
||||
## NEXT REAL-DATA MILESTONE — A6000 ENGINE BAY END-TO-END
|
||||
## NEXT REAL-DATA MILESTONE — A6000 + S21 ENGINE BAY MULTI-CAMPAIGN INTEGRATION
|
||||
|
||||
1. confirmer explicitement les 953 propositions ARW/JPEG ;
|
||||
2. matérialiser progressivement environ 953 Captures ;
|
||||
3. produire les représentations scientifiques par lots gouvernés ;
|
||||
4. exécuter features, candidats, matching, vérification, tracks et Sparse SfM ;
|
||||
5. évaluer la qualité de la reconstruction sparse ;
|
||||
6. exécuter MVS/dense avec budgets et scratch contrôlés ;
|
||||
7. publier durablement nuage dense et mesh ;
|
||||
8. comparer le résultat aux tentatives photogrammétriques antérieures.
|
||||
1. confirmer explicitement et exécuter les campagnes A6000 et S21 ;
|
||||
2. matérialiser progressivement leurs Captures et représentations scientifiques
|
||||
par lots gouvernés ;
|
||||
3. exécuter features, candidats, matching, vérification, tracks et Sparse SfM ;
|
||||
4. évaluer la qualité de la reconstruction sparse multi-campagne ;
|
||||
5. exécuter MVS/dense avec budgets et scratch contrôlés ;
|
||||
6. publier durablement nuage dense et mesh ;
|
||||
7. comparer le résultat aux tentatives photogrammétriques antérieures.
|
||||
|
||||
Ce milestone est une intégration réelle, pas une nouvelle série de micro-gates
|
||||
S3. Les antécédents d'OOM/SIGSEGV OpenMVS, pression swap, grands intermédiaires
|
||||
|
|
@ -204,7 +214,8 @@ Le but à long terme n'est pas seulement de reconstruire ce qui a été
|
|||
photographié, mais de guider activement l'opérateur vers les photographies qui
|
||||
manquent encore pour obtenir une reconstruction fiable. Cette capacité est
|
||||
postérieure à une reconstruction suffisamment mature ; elle ne fait pas partie
|
||||
de S3 et ne remplace pas la prochaine tranche d'exécution durable de campagne.
|
||||
de S3 et ne remplace pas le prochain milestone d'intégration multi-campagne
|
||||
A6000 + S21.
|
||||
|
||||
```text
|
||||
photographies existantes
|
||||
|
|
@ -421,10 +432,8 @@ L'ordre demeure sans ambiguïté :
|
|||
|
||||
```text
|
||||
CURRENT NEXT
|
||||
exécution durable de campagne (Task / Queue / Scheduler / Governor,
|
||||
confirmations durables, progression et reprise)
|
||||
→ INTÉGRATION RÉELLE
|
||||
campagnes A6000 + S21 → pipeline scientifique → dense/mesh → publication
|
||||
intégration réelle multi-campagne A6000 + S21
|
||||
→ pipeline scientifique → dense/mesh → publication
|
||||
→ LATER
|
||||
Coverage Analysis → Coverage Viewer → suggestions de points de vue
|
||||
→ localisation live → intégration HDMI/USB → Capture Guidance / Live Coverage
|
||||
|
|
@ -448,8 +457,8 @@ scientifique.
|
|||
- ALIKED tant que provenance modèle, export ONNX et oracle upstream ne sont pas
|
||||
reproductibles.
|
||||
|
||||
Ces idées ne doivent pas devancer l'exécution durable de campagne ni créer un
|
||||
second runtime, Governor ou système de persistance.
|
||||
Ces idées ne doivent pas devancer l'intégration réelle multi-campagne ni créer
|
||||
un second runtime, Governor ou système de persistance.
|
||||
|
||||
## Principes de séquencement
|
||||
|
||||
|
|
|
|||
63
include/lardon3d/acquisition_campaign_task.h
Normal file
63
include/lardon3d/acquisition_campaign_task.h
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#ifndef LARDON3D_ACQUISITION_CAMPAIGN_TASK_H
|
||||
#define LARDON3D_ACQUISITION_CAMPAIGN_TASK_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <lardon3d/acquisition_campaign.h>
|
||||
#include <lardon3d/task_kind_registry.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND "acquisition_campaign.run"
|
||||
enum {
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND_VERSION = 1,
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_REQUEST_VERSION = 1,
|
||||
};
|
||||
|
||||
/* Derived solely from the frozen source, path, confirmation and group bounds.
|
||||
*/
|
||||
#define LARDON3D_ACQUISITION_CAMPAIGN_TASK_REQUEST_MAX_BYTES \
|
||||
((size_t)LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES * \
|
||||
(LARDON3D_ACQUISITION_CAMPAIGN_PATH_CAPACITY + 700u) + \
|
||||
(size_t)LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES * \
|
||||
(4u + 4u * LARDON3D_ACQUISITION_INGEST_MAX_SOURCES) + \
|
||||
128u)
|
||||
|
||||
typedef struct {
|
||||
const Lardon3DAcquisitionCampaignSource *sources;
|
||||
size_t source_count;
|
||||
const Lardon3DAcquisitionCampaignConfirmation *confirmations;
|
||||
size_t confirmation_count;
|
||||
Lardon3DAcquisitionIngestOptions ingest_options;
|
||||
} Lardon3DAcquisitionCampaignTaskRequest;
|
||||
|
||||
Lardon3DTask *lardon3d_project_create_acquisition_campaign_task(
|
||||
Lardon3DAppState *state, uint64_t scanset_id,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *request, uint64_t *task_id);
|
||||
bool lardon3d_project_enqueue_acquisition_campaign(
|
||||
Lardon3DAppState *state, uint64_t scanset_id,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *request, uint64_t *task_id);
|
||||
bool lardon3d_acquisition_campaign_task_reconstruct(
|
||||
const Lardon3DTaskDurableSnapshot *snapshot, void *context,
|
||||
Lardon3DTaskKindBinding *binding);
|
||||
|
||||
/* Exposed for deterministic codec validation without executing ingestion. */
|
||||
bool lardon3d_acquisition_campaign_request_encode(
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *request,
|
||||
unsigned char *output, size_t capacity, size_t *size);
|
||||
bool lardon3d_acquisition_campaign_request_decode(
|
||||
const unsigned char *input, size_t size,
|
||||
Lardon3DAcquisitionCampaignSource *sources, size_t source_capacity,
|
||||
Lardon3DAcquisitionCampaignConfirmation *confirmations,
|
||||
size_t confirmation_capacity,
|
||||
Lardon3DAcquisitionCampaignTaskRequest *request);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -58,6 +58,9 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_task(Lardon3DApp
|
|||
Lardon3DProjectTaskCheckpointResult
|
||||
lardon3d_project_checkpoint_image_import_task(Lardon3DAppState *state, const Lardon3DTask *task,
|
||||
const char *source_path, uint64_t scanset_id);
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_acquisition_campaign_task(
|
||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *parameters);
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_task(
|
||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||
const Lardon3DProjectDbFeatureExtractTask *parameters);
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
#include <lardon3d/sparse_sfm_incremental.h>
|
||||
|
||||
enum {
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 19,
|
||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 20,
|
||||
LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
|
||||
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,
|
||||
|
|
@ -100,6 +100,20 @@ typedef struct {
|
|||
uint64_t scanset_id;
|
||||
} Lardon3DProjectDbImageImport;
|
||||
|
||||
typedef struct {
|
||||
uint64_t task_id;
|
||||
uint64_t scanset_id;
|
||||
uint32_t next_group_id;
|
||||
uint32_t group_count;
|
||||
const unsigned char *request;
|
||||
size_t request_size;
|
||||
} Lardon3DProjectDbAcquisitionCampaignTask;
|
||||
|
||||
typedef struct {
|
||||
uint32_t group_id;
|
||||
uint64_t capture_id;
|
||||
} Lardon3DProjectDbAcquisitionCampaignCapture;
|
||||
|
||||
typedef struct {
|
||||
uint64_t scanset_id;
|
||||
char name[LARDON3D_PROJECT_DB_SCANSET_NAME_CAPACITY];
|
||||
|
|
@ -570,6 +584,20 @@ Lardon3DProjectDbResult lardon3d_project_db_list_candidate_pairs(
|
|||
Lardon3DProjectDbResult
|
||||
lardon3d_project_db_load_image_import(Lardon3DProjectDb *database, uint64_t task_id,
|
||||
Lardon3DProjectDbImageImport *parameters);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_acquisition_campaign_task(
|
||||
Lardon3DProjectDb *database, const Lardon3DTaskDurableSnapshot *snapshot,
|
||||
const char *task_kind, uint32_t task_kind_version,
|
||||
const Lardon3DProjectDbCheckpoint *checkpoint,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *parameters, int64_t updated_at);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_acquisition_campaign_task(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, unsigned char *request,
|
||||
size_t request_capacity, Lardon3DProjectDbAcquisitionCampaignTask *parameters);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, uint32_t group_id,
|
||||
uint64_t capture_id, uint32_t next_group_id);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_acquisition_campaign_capture(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, uint32_t group_id,
|
||||
Lardon3DProjectDbAcquisitionCampaignCapture *capture);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_allocate_task_id(Lardon3DProjectDb *database,
|
||||
uint64_t *task_id);
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_task(Lardon3DProjectDb *database, uint64_t task_id,
|
||||
|
|
|
|||
20
meson.build
20
meson.build
|
|
@ -152,6 +152,7 @@ executable(
|
|||
'src/acquisition_pairing.cpp',
|
||||
'src/acquisition_ingest.cpp',
|
||||
'src/acquisition_campaign.cpp',
|
||||
'src/acquisition_campaign_task.cpp',
|
||||
'src/feature_extractor_opencv.cpp',
|
||||
'src/feature_store.c',
|
||||
'src/feature_extractor_opencv.cpp',
|
||||
|
|
@ -195,6 +196,7 @@ executable(
|
|||
'-DLARDON3D_TRACK_BUILDER_TASK_AVAILABLE',
|
||||
'-DLARDON3D_SPARSE_SFM_TASK_AVAILABLE',
|
||||
'-DLARDON3D_INCREMENTAL_RECONSTRUCTION_TASK_AVAILABLE',
|
||||
'-DLARDON3D_ACQUISITION_CAMPAIGN_TASK_AVAILABLE',
|
||||
],
|
||||
dependencies: [
|
||||
ncursesw,
|
||||
|
|
@ -377,6 +379,24 @@ acquisition_campaign_test = executable(
|
|||
|
||||
test('acquisition-campaign', acquisition_campaign_test, timeout: 30)
|
||||
|
||||
acquisition_campaign_task_test = executable(
|
||||
'test-acquisition-campaign-task',
|
||||
sources: [
|
||||
'tests/test_acquisition_campaign_task.cpp',
|
||||
'src/acquisition_campaign_task.cpp', 'src/acquisition_campaign.cpp',
|
||||
'src/acquisition_ingest.cpp', 'src/acquisition_pairing.cpp',
|
||||
'src/raw_development.cpp', 'src/app_state.c', 'src/image_catalog_persistent.c',
|
||||
'src/image_catalog.c', 'src/image_view.c', 'src/task_kind_registry.c',
|
||||
'src/project.c', 'src/project_db.c', 'src/project_db_sparse_sfm.c',
|
||||
'src/task.c', 'src/task_checkpoint.c', 'src/task_queue.c',
|
||||
'src/resource_governor.c', 'src/resource_snapshot.c',
|
||||
],
|
||||
include_directories: include_directories('include'),
|
||||
cpp_args: ['-DLARDON3D_ACQUISITION_CAMPAIGN_TASK_TESTING'],
|
||||
dependencies: [threads, sqlite3, openssl, opencv, libraw, libexif, libpng, libdeflate],
|
||||
)
|
||||
test('acquisition-campaign-task', acquisition_campaign_task_test, timeout: 30)
|
||||
|
||||
feature_store_test = executable(
|
||||
'test-feature-store',
|
||||
sources: [
|
||||
|
|
|
|||
569
src/acquisition_campaign_task.cpp
Normal file
569
src/acquisition_campaign_task.cpp
Normal file
|
|
@ -0,0 +1,569 @@
|
|||
extern "C" {
|
||||
#include <lardon3d/acquisition_campaign_task.h>
|
||||
#include <lardon3d/project.h>
|
||||
#include <lardon3d/project_db.h>
|
||||
#include <lardon3d/task_queue.h>
|
||||
}
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <new>
|
||||
#include <vector>
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr unsigned char magic[8] = {'L', '3', 'D', 'A', 'C', 'T', '1', '\0'};
|
||||
constexpr size_t max_request_size =
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_TASK_REQUEST_MAX_BYTES;
|
||||
|
||||
struct Writer {
|
||||
unsigned char *p;
|
||||
size_t left;
|
||||
size_t used;
|
||||
bool bytes(const void *v, size_t n) {
|
||||
if (n > left)
|
||||
return false;
|
||||
if (p)
|
||||
std::memcpy(p + used, v, n);
|
||||
used += n;
|
||||
left -= n;
|
||||
return true;
|
||||
}
|
||||
bool u16(uint16_t v) {
|
||||
unsigned char b[2] = {static_cast<unsigned char>(v),
|
||||
static_cast<unsigned char>(v >> 8)};
|
||||
return bytes(b, 2);
|
||||
}
|
||||
bool u32(uint32_t v) {
|
||||
unsigned char b[4];
|
||||
for (int i = 0; i < 4; ++i)
|
||||
b[i] = static_cast<unsigned char>(v >> (8 * i));
|
||||
return bytes(b, 4);
|
||||
}
|
||||
bool u64(uint64_t v) {
|
||||
unsigned char b[8];
|
||||
for (int i = 0; i < 8; ++i)
|
||||
b[i] = static_cast<unsigned char>(v >> (8 * i));
|
||||
return bytes(b, 8);
|
||||
}
|
||||
bool text(const char *s, size_t cap) {
|
||||
if (!s)
|
||||
return false;
|
||||
const void *end = std::memchr(s, '\0', cap);
|
||||
if (!end)
|
||||
return false;
|
||||
size_t n = static_cast<const char *>(end) - s;
|
||||
return n <= UINT16_MAX && u16(static_cast<uint16_t>(n)) && bytes(s, n);
|
||||
}
|
||||
};
|
||||
|
||||
struct Reader {
|
||||
const unsigned char *p;
|
||||
size_t left;
|
||||
bool bytes(void *v, size_t n) {
|
||||
if (n > left)
|
||||
return false;
|
||||
std::memcpy(v, p, n);
|
||||
p += n;
|
||||
left -= n;
|
||||
return true;
|
||||
}
|
||||
bool u16(uint16_t &v) {
|
||||
unsigned char b[2];
|
||||
if (!bytes(b, 2))
|
||||
return false;
|
||||
v = uint16_t(b[0]) | uint16_t(uint16_t(b[1]) << 8);
|
||||
return true;
|
||||
}
|
||||
bool u32(uint32_t &v) {
|
||||
unsigned char b[4];
|
||||
if (!bytes(b, 4))
|
||||
return false;
|
||||
v = 0;
|
||||
for (int i = 3; i >= 0; --i)
|
||||
v = (v << 8) | b[i];
|
||||
return true;
|
||||
}
|
||||
bool u64(uint64_t &v) {
|
||||
unsigned char b[8];
|
||||
if (!bytes(b, 8))
|
||||
return false;
|
||||
v = 0;
|
||||
for (int i = 7; i >= 0; --i)
|
||||
v = (v << 8) | b[i];
|
||||
return true;
|
||||
}
|
||||
bool text(char *s, size_t cap) {
|
||||
uint16_t n;
|
||||
if (!u16(n) || size_t(n) >= cap || size_t(n) > left)
|
||||
return false;
|
||||
std::memcpy(s, p, n);
|
||||
s[n] = '\0';
|
||||
p += n;
|
||||
left -= n;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
bool encode(const Lardon3DAcquisitionCampaignTaskRequest *r, Writer &w) {
|
||||
if (!r || !r->sources || r->source_count == 0 ||
|
||||
r->source_count > LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES ||
|
||||
(r->confirmation_count && !r->confirmations) ||
|
||||
r->confirmation_count > r->source_count ||
|
||||
r->ingest_options.representation <
|
||||
LARDON3D_ACQUISITION_SELECT_JPEG_SOURCE ||
|
||||
r->ingest_options.representation >
|
||||
LARDON3D_ACQUISITION_SELECT_DEVELOP_RAW ||
|
||||
r->ingest_options.select_representation > 1u ||
|
||||
r->ingest_options.imported_at < 0 ||
|
||||
r->ingest_options.max_source_bytes == 0u)
|
||||
return false;
|
||||
std::unique_ptr<Lardon3DAcquisitionCampaignPlan> validated(
|
||||
new (std::nothrow) Lardon3DAcquisitionCampaignPlan{});
|
||||
if (!validated ||
|
||||
lardon3d_acquisition_campaign_plan(
|
||||
r->sources, r->source_count, r->confirmations, r->confirmation_count,
|
||||
validated.get()) != LARDON3D_ACQUISITION_CAMPAIGN_OK ||
|
||||
validated->group_count == 0)
|
||||
return false;
|
||||
if (!w.bytes(magic, sizeof(magic)) ||
|
||||
!w.u32(LARDON3D_ACQUISITION_CAMPAIGN_REQUEST_VERSION) ||
|
||||
!w.u32(static_cast<uint32_t>(r->source_count)) ||
|
||||
!w.u32(static_cast<uint32_t>(r->confirmation_count)) ||
|
||||
!w.u32(static_cast<uint32_t>(r->ingest_options.representation)) ||
|
||||
!w.u32(r->ingest_options.select_representation ? 1u : 0u) ||
|
||||
!w.u64(static_cast<uint64_t>(r->ingest_options.imported_at)) ||
|
||||
!w.u64(r->ingest_options.max_source_bytes))
|
||||
return false;
|
||||
for (size_t i = 0; i < r->source_count; ++i) {
|
||||
const auto &s = r->sources[i];
|
||||
const auto &m = s.metadata;
|
||||
if (!w.text(s.path, sizeof(s.path)) ||
|
||||
!w.u32(static_cast<uint32_t>(s.source_kind)) ||
|
||||
!w.u32(static_cast<uint32_t>(s.metadata_result)) ||
|
||||
!w.u32(m.policy_version) ||
|
||||
!w.u32(static_cast<uint32_t>(m.source_kind)) ||
|
||||
!w.u32(m.present_fields) || !w.text(m.make, sizeof(m.make)) ||
|
||||
!w.text(m.model, sizeof(m.model)) ||
|
||||
!w.text(m.body_serial, sizeof(m.body_serial)) ||
|
||||
!w.text(m.datetime_original, sizeof(m.datetime_original)) ||
|
||||
!w.text(m.subsec_original, sizeof(m.subsec_original)) ||
|
||||
!w.text(m.offset_original, sizeof(m.offset_original)) ||
|
||||
!w.text(m.image_unique_id, sizeof(m.image_unique_id)) ||
|
||||
!w.u32(m.width) || !w.u32(m.height) || !w.u16(m.orientation))
|
||||
return false;
|
||||
}
|
||||
for (size_t i = 0; i < r->confirmation_count; ++i) {
|
||||
const auto &c = r->confirmations[i];
|
||||
if (c.source_count == 0 ||
|
||||
c.source_count > LARDON3D_ACQUISITION_INGEST_MAX_SOURCES ||
|
||||
!w.u32(static_cast<uint32_t>(c.source_count)))
|
||||
return false;
|
||||
for (size_t j = 0; j < c.source_count; ++j)
|
||||
if (c.source_indices[j] >= r->source_count ||
|
||||
!w.u32(static_cast<uint32_t>(c.source_indices[j])))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Context {
|
||||
char project_path[LARDON3D_APP_STATE_PATH_CAPACITY]{};
|
||||
Lardon3DProjectDb *db{};
|
||||
Lardon3DResourceGovernor *governor{};
|
||||
uint64_t scanset{};
|
||||
std::vector<Lardon3DAcquisitionCampaignSource> sources;
|
||||
std::vector<Lardon3DAcquisitionCampaignConfirmation> confirmations;
|
||||
std::vector<unsigned char> encoded;
|
||||
Lardon3DAcquisitionCampaignPlan plan{};
|
||||
Lardon3DAcquisitionIngestOptions options{};
|
||||
};
|
||||
|
||||
void destroy(void *p) { delete static_cast<Context *>(p); }
|
||||
void runtime(Context *c, Lardon3DAppState &s) {
|
||||
lardon3d_app_state_init(&s);
|
||||
s.project_loaded = true;
|
||||
s.project_db = c->db;
|
||||
s.resource_governor = c->governor;
|
||||
std::snprintf(s.project_path, sizeof(s.project_path), "%s", c->project_path);
|
||||
}
|
||||
|
||||
bool checkpoint(Context *c, Lardon3DTask *t, uint32_t cursor) {
|
||||
Lardon3DAppState s;
|
||||
runtime(c, s);
|
||||
Lardon3DProjectDbAcquisitionCampaignTask p{
|
||||
lardon3d_task_id(t),
|
||||
c->scanset,
|
||||
cursor,
|
||||
static_cast<uint32_t>(c->plan.group_count),
|
||||
c->encoded.data(),
|
||||
c->encoded.size()};
|
||||
return lardon3d_project_checkpoint_acquisition_campaign_task(&s, t, &p) ==
|
||||
LARDON3D_PROJECT_TASK_CHECKPOINT_OK;
|
||||
}
|
||||
bool run_impl(Lardon3DTask *t, void *p) {
|
||||
auto *c = static_cast<Context *>(p);
|
||||
Lardon3DProjectDbAcquisitionCampaignTask persisted{};
|
||||
std::vector<unsigned char> blob(max_request_size);
|
||||
if (lardon3d_project_db_load_acquisition_campaign_task(
|
||||
c->db, lardon3d_task_id(t), blob.data(), blob.size(), &persisted) !=
|
||||
LARDON3D_PROJECT_DB_OK)
|
||||
return lardon3d_task_fail(t, "Campagne durable introuvable.");
|
||||
for (uint32_t cursor = persisted.next_group_id; cursor < c->plan.group_count;
|
||||
++cursor) {
|
||||
const uint32_t group_id = cursor + 1u;
|
||||
if (!lardon3d_task_checkpoint(t))
|
||||
return false;
|
||||
Lardon3DProjectDbAcquisitionCampaignCapture retained{};
|
||||
uint64_t resume = 0;
|
||||
auto lr = lardon3d_project_db_load_acquisition_campaign_capture(
|
||||
c->db, lardon3d_task_id(t), group_id, &retained);
|
||||
if (lr == LARDON3D_PROJECT_DB_OK)
|
||||
resume = retained.capture_id;
|
||||
else if (lr != LARDON3D_PROJECT_DB_NOT_FOUND)
|
||||
return lardon3d_task_fail(t, "Lecture de rétention impossible.");
|
||||
auto options = c->options;
|
||||
options.grouping = LARDON3D_ACQUISITION_GROUP_CALLER_EXPLICIT;
|
||||
options.resume_capture_id = resume;
|
||||
options.producer_task_id = lardon3d_task_id(t);
|
||||
Lardon3DAcquisitionIngestOutput out{};
|
||||
Lardon3DAcquisitionIngestResult ir{};
|
||||
Lardon3DAppState s;
|
||||
runtime(c, s);
|
||||
auto cr = lardon3d_acquisition_campaign_materialize_group(
|
||||
&s, c->scanset, c->sources.data(), c->sources.size(), &c->plan,
|
||||
group_id, &options, &out, &ir);
|
||||
if (cr != LARDON3D_ACQUISITION_CAMPAIGN_OK ||
|
||||
ir != LARDON3D_ACQUISITION_INGEST_OK || out.group_count != 1)
|
||||
return lardon3d_task_fail(t, "Échec de matérialisation de campagne.");
|
||||
#ifdef LARDON3D_ACQUISITION_CAMPAIGN_TASK_TESTING
|
||||
const char *before_retention =
|
||||
std::getenv("LARDON3D_TEST_CAMPAIGN_FAIL_BEFORE_RETENTION");
|
||||
if (before_retention && std::strcmp(before_retention, "1") == 0)
|
||||
return lardon3d_task_fail(t, "Échec injecté avant rétention.");
|
||||
#endif
|
||||
if (lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
c->db, lardon3d_task_id(t), group_id, out.groups[0].capture_id,
|
||||
group_id) != LARDON3D_PROJECT_DB_OK)
|
||||
return lardon3d_task_fail(t, "Rétention de Capture impossible.");
|
||||
#ifdef LARDON3D_ACQUISITION_CAMPAIGN_TASK_TESTING
|
||||
const char *after_retention =
|
||||
std::getenv("LARDON3D_TEST_CAMPAIGN_FAIL_AFTER_RETENTION");
|
||||
if (after_retention && std::strcmp(after_retention, "1") == 0)
|
||||
return lardon3d_task_fail(t, "Échec injecté après rétention.");
|
||||
#endif
|
||||
unsigned progress = static_cast<unsigned>(
|
||||
(uint64_t(group_id) * 100u / c->plan.group_count));
|
||||
if (!lardon3d_task_set_progress(t, progress,
|
||||
"Groupe de campagne matérialisé.") ||
|
||||
!checkpoint(c, t, group_id))
|
||||
return lardon3d_task_fail(t, "Checkpoint de campagne impossible.");
|
||||
if (group_id < c->plan.group_count) {
|
||||
Lardon3DTaskExecutionContract contract{};
|
||||
Lardon3DResourceReservation *reservation = nullptr;
|
||||
if (!lardon3d_task_sequence_break(t, c->governor, &reservation,
|
||||
&contract))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool run(Lardon3DTask *t, void *p) noexcept {
|
||||
try {
|
||||
return run_impl(t, p);
|
||||
} catch (const std::bad_alloc &) {
|
||||
return lardon3d_task_fail(t, "Mémoire insuffisante pour la campagne.");
|
||||
} catch (...) {
|
||||
return lardon3d_task_fail(t, "Erreur interne de campagne.");
|
||||
}
|
||||
}
|
||||
void finished(const Lardon3DTask *t, void *p) {
|
||||
try {
|
||||
auto *c = static_cast<Context *>(p);
|
||||
Lardon3DAppState s;
|
||||
runtime(c, s);
|
||||
(void)lardon3d_project_checkpoint_task(&s, t);
|
||||
} catch (...) {
|
||||
}
|
||||
}
|
||||
|
||||
Context *make_context(const char *path, Lardon3DProjectDb *db,
|
||||
Lardon3DResourceGovernor *g, uint64_t scanset,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest &r,
|
||||
const unsigned char *encoded, size_t n) {
|
||||
if (!path || !path[0])
|
||||
return nullptr;
|
||||
std::unique_ptr<Context> c(new (std::nothrow) Context);
|
||||
if (!c)
|
||||
return nullptr;
|
||||
const int path_size =
|
||||
std::snprintf(c->project_path, sizeof(c->project_path), "%s", path);
|
||||
if (path_size < 0 || static_cast<size_t>(path_size) >= sizeof(c->project_path))
|
||||
return nullptr;
|
||||
c->db = db;
|
||||
c->governor = g;
|
||||
c->scanset = scanset;
|
||||
c->sources.assign(r.sources, r.sources + r.source_count);
|
||||
c->confirmations.assign(r.confirmations,
|
||||
r.confirmations + r.confirmation_count);
|
||||
c->options = r.ingest_options;
|
||||
c->encoded.assign(encoded, encoded + n);
|
||||
if (lardon3d_acquisition_campaign_plan(c->sources.data(), c->sources.size(),
|
||||
c->confirmations.data(),
|
||||
c->confirmations.size(), &c->plan) !=
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_OK ||
|
||||
c->plan.group_count == 0)
|
||||
return nullptr;
|
||||
return c.release();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool request_encode_impl(
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *r, unsigned char *out,
|
||||
size_t cap, size_t *size) {
|
||||
if (size)
|
||||
*size = 0;
|
||||
if (!size)
|
||||
return false;
|
||||
Writer measure{nullptr, max_request_size, 0};
|
||||
if (!encode(r, measure) || measure.used > max_request_size) {
|
||||
return false;
|
||||
}
|
||||
*size = measure.used;
|
||||
if (!out)
|
||||
return cap == 0;
|
||||
if (cap < measure.used)
|
||||
return false;
|
||||
Writer writer{out, cap, 0};
|
||||
return encode(r, writer) && writer.used == measure.used;
|
||||
}
|
||||
|
||||
bool request_decode_impl(
|
||||
const unsigned char *input, size_t size,
|
||||
Lardon3DAcquisitionCampaignSource *sources, size_t sc,
|
||||
Lardon3DAcquisitionCampaignConfirmation *confirmations, size_t cc,
|
||||
Lardon3DAcquisitionCampaignTaskRequest *r) {
|
||||
if (!input || !r || size > max_request_size)
|
||||
return false;
|
||||
std::memset(r, 0, sizeof(*r));
|
||||
Reader q{input, size};
|
||||
unsigned char m[8];
|
||||
uint32_t version, n, c, rep, select;
|
||||
uint64_t imported, maxbytes;
|
||||
if (!q.bytes(m, 8) || std::memcmp(m, magic, 8) || !q.u32(version) ||
|
||||
version != 1 || !q.u32(n) || n == 0 || n > sc ||
|
||||
n > LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES || !q.u32(c) || c > cc ||
|
||||
c > n || !sources || (c > 0 && !confirmations) || !q.u32(rep) ||
|
||||
rep < 1 || rep > 2 || !q.u32(select) || select > 1 ||
|
||||
!q.u64(imported) || imported > INT64_MAX || !q.u64(maxbytes) ||
|
||||
maxbytes == 0u)
|
||||
return false;
|
||||
std::memset(sources, 0, n * sizeof(*sources));
|
||||
std::memset(confirmations, 0, c * sizeof(*confirmations));
|
||||
for (uint32_t i = 0; i < n; ++i) {
|
||||
auto &s = sources[i];
|
||||
auto &md = s.metadata;
|
||||
uint32_t sk, mr, msk;
|
||||
if (!q.text(s.path, sizeof(s.path)) || !q.u32(sk) || sk > 2 || !q.u32(mr) ||
|
||||
mr > LARDON3D_ACQUISITION_INTERNAL_ERROR || !q.u32(md.policy_version) ||
|
||||
!q.u32(msk) || msk > 2 || !q.u32(md.present_fields) ||
|
||||
!q.text(md.make, sizeof(md.make)) ||
|
||||
!q.text(md.model, sizeof(md.model)) ||
|
||||
!q.text(md.body_serial, sizeof(md.body_serial)) ||
|
||||
!q.text(md.datetime_original, sizeof(md.datetime_original)) ||
|
||||
!q.text(md.subsec_original, sizeof(md.subsec_original)) ||
|
||||
!q.text(md.offset_original, sizeof(md.offset_original)) ||
|
||||
!q.text(md.image_unique_id, sizeof(md.image_unique_id)) ||
|
||||
!q.u32(md.width) || !q.u32(md.height) || !q.u16(md.orientation))
|
||||
return false;
|
||||
s.source_kind = static_cast<Lardon3DAcquisitionSourceKind>(sk);
|
||||
s.metadata_result = static_cast<Lardon3DAcquisitionResult>(mr);
|
||||
md.source_kind = static_cast<Lardon3DAcquisitionSourceKind>(msk);
|
||||
}
|
||||
for (uint32_t i = 0; i < c; ++i) {
|
||||
uint32_t count;
|
||||
if (!q.u32(count) || count == 0 ||
|
||||
count > LARDON3D_ACQUISITION_INGEST_MAX_SOURCES)
|
||||
return false;
|
||||
confirmations[i].source_count = count;
|
||||
for (uint32_t j = 0; j < count; ++j) {
|
||||
uint32_t index;
|
||||
if (!q.u32(index) || index >= n)
|
||||
return false;
|
||||
confirmations[i].source_indices[j] = index;
|
||||
}
|
||||
}
|
||||
if (q.left)
|
||||
return false;
|
||||
r->sources = sources;
|
||||
r->source_count = n;
|
||||
r->confirmations = confirmations;
|
||||
r->confirmation_count = c;
|
||||
r->ingest_options.representation =
|
||||
static_cast<Lardon3DAcquisitionRepresentation>(rep);
|
||||
r->ingest_options.select_representation = static_cast<uint8_t>(select);
|
||||
r->ingest_options.imported_at = static_cast<int64_t>(imported);
|
||||
r->ingest_options.max_source_bytes = maxbytes;
|
||||
std::unique_ptr<Lardon3DAcquisitionCampaignPlan> validated(
|
||||
new (std::nothrow) Lardon3DAcquisitionCampaignPlan{});
|
||||
return validated &&
|
||||
lardon3d_acquisition_campaign_plan(sources, n, confirmations, c,
|
||||
validated.get()) ==
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_OK &&
|
||||
validated->group_count > 0;
|
||||
}
|
||||
|
||||
bool task_reconstruct_impl(
|
||||
const Lardon3DTaskDurableSnapshot *s, void *userdata,
|
||||
Lardon3DTaskKindBinding *b) {
|
||||
auto *rt = static_cast<Lardon3DTaskReconstructionContext *>(userdata);
|
||||
if (!s || !rt || !b)
|
||||
return false;
|
||||
std::vector<unsigned char> blob(max_request_size);
|
||||
Lardon3DProjectDbAcquisitionCampaignTask p{};
|
||||
if (lardon3d_project_db_load_acquisition_campaign_task(
|
||||
rt->project_db, s->id, blob.data(), blob.size(), &p) !=
|
||||
LARDON3D_PROJECT_DB_OK)
|
||||
return false;
|
||||
std::vector<Lardon3DAcquisitionCampaignSource> sources(
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES);
|
||||
std::vector<Lardon3DAcquisitionCampaignConfirmation> confirmations(
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_MAX_SOURCES);
|
||||
Lardon3DAcquisitionCampaignTaskRequest r{};
|
||||
if (!lardon3d_acquisition_campaign_request_decode(
|
||||
blob.data(), p.request_size, sources.data(), sources.size(),
|
||||
confirmations.data(), confirmations.size(), &r))
|
||||
return false;
|
||||
auto *c =
|
||||
make_context(rt->project_path, rt->project_db, rt->resource_governor,
|
||||
p.scanset_id, r, blob.data(), p.request_size);
|
||||
if (!c)
|
||||
return false;
|
||||
*b = {run, c, destroy, finished, c};
|
||||
return true;
|
||||
}
|
||||
|
||||
Lardon3DTask *create_task_impl(
|
||||
Lardon3DAppState *s, uint64_t scanset,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *r, uint64_t *id) {
|
||||
if (id)
|
||||
*id = 0;
|
||||
if (!s || !s->project_loaded || !s->project_db || !s->resource_governor ||
|
||||
!r || !id)
|
||||
return nullptr;
|
||||
Lardon3DProjectDbScanSet ss{};
|
||||
if (lardon3d_project_db_load_scanset(s->project_db, scanset, &ss) !=
|
||||
LARDON3D_PROJECT_DB_OK)
|
||||
return nullptr;
|
||||
size_t n = 0;
|
||||
if (!lardon3d_acquisition_campaign_request_encode(r, nullptr, 0, &n))
|
||||
return nullptr;
|
||||
std::vector<unsigned char> blob(n);
|
||||
if (!lardon3d_acquisition_campaign_request_encode(r, blob.data(), blob.size(),
|
||||
&n))
|
||||
return nullptr;
|
||||
auto *c = make_context(s->project_path, s->project_db, s->resource_governor,
|
||||
scanset, *r, blob.data(), n);
|
||||
if (!c)
|
||||
return nullptr;
|
||||
uint64_t task_id;
|
||||
if (lardon3d_project_db_allocate_task_id(s->project_db, &task_id) !=
|
||||
LARDON3D_PROJECT_DB_OK) {
|
||||
delete c;
|
||||
return nullptr;
|
||||
}
|
||||
Lardon3DResourceEstimate e{
|
||||
256 * 1024, 0, 64 * 1024, 0, 1,
|
||||
1, 1, 0, 1, LARDON3D_RESOURCE_TASK_IMPORT};
|
||||
auto *t = lardon3d_task_create_typed("Campagne d'acquisition", &e,
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND,
|
||||
1, run, c, destroy);
|
||||
if (!t || !lardon3d_task_assign_id(t, task_id) ||
|
||||
!lardon3d_task_set_finished_callback(t, finished, c) ||
|
||||
!checkpoint(c, t, 0)) {
|
||||
lardon3d_task_destroy(t);
|
||||
return nullptr;
|
||||
}
|
||||
*id = task_id;
|
||||
return t;
|
||||
}
|
||||
|
||||
extern "C" bool lardon3d_acquisition_campaign_request_encode(
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *r, unsigned char *out,
|
||||
size_t cap, size_t *size) {
|
||||
try {
|
||||
return request_encode_impl(r, out, cap, size);
|
||||
} catch (const std::bad_alloc &) {
|
||||
if (size)
|
||||
*size = 0;
|
||||
return false;
|
||||
} catch (...) {
|
||||
if (size)
|
||||
*size = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" bool lardon3d_acquisition_campaign_request_decode(
|
||||
const unsigned char *input, size_t size,
|
||||
Lardon3DAcquisitionCampaignSource *sources, size_t sc,
|
||||
Lardon3DAcquisitionCampaignConfirmation *confirmations, size_t cc,
|
||||
Lardon3DAcquisitionCampaignTaskRequest *r) {
|
||||
try {
|
||||
return request_decode_impl(input, size, sources, sc, confirmations, cc, r);
|
||||
} catch (const std::bad_alloc &) {
|
||||
return false;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" bool lardon3d_acquisition_campaign_task_reconstruct(
|
||||
const Lardon3DTaskDurableSnapshot *s, void *userdata,
|
||||
Lardon3DTaskKindBinding *b) {
|
||||
try {
|
||||
return task_reconstruct_impl(s, userdata, b);
|
||||
} catch (const std::bad_alloc &) {
|
||||
return false;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" Lardon3DTask *lardon3d_project_create_acquisition_campaign_task(
|
||||
Lardon3DAppState *s, uint64_t scanset,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *r, uint64_t *id) {
|
||||
if (id)
|
||||
*id = 0;
|
||||
try {
|
||||
return create_task_impl(s, scanset, r, id);
|
||||
} catch (const std::bad_alloc &) {
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" bool lardon3d_project_enqueue_acquisition_campaign(
|
||||
Lardon3DAppState *s, uint64_t scanset,
|
||||
const Lardon3DAcquisitionCampaignTaskRequest *r, uint64_t *id) {
|
||||
try {
|
||||
if (!s || !s->task_queue)
|
||||
return false;
|
||||
auto *t =
|
||||
lardon3d_project_create_acquisition_campaign_task(s, scanset, r, id);
|
||||
if (!t)
|
||||
return false;
|
||||
if (!lardon3d_task_queue_add(s->task_queue, t, nullptr)) {
|
||||
lardon3d_task_destroy(t);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} catch (const std::bad_alloc &) {
|
||||
return false;
|
||||
} catch (...) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -674,7 +674,8 @@ checkpoint_task_internal(Lardon3DAppState *state, const Lardon3DTask *task,
|
|||
const Lardon3DProjectDbVisualIndexUpdateTask *visual_parameters,
|
||||
const Lardon3DProjectDbCandidatePairGenerateTask *candidate_parameters,
|
||||
const Lardon3DProjectDbMatcherTask *matcher_parameters,
|
||||
const Lardon3DProjectDbGeometricVerifierTask *geometric_parameters) {
|
||||
const Lardon3DProjectDbGeometricVerifierTask *geometric_parameters,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *campaign_parameters) {
|
||||
if (!state || !state->project_loaded || !state->project_db) {
|
||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_NO_PROJECT;
|
||||
}
|
||||
|
|
@ -741,6 +742,10 @@ checkpoint_task_internal(Lardon3DAppState *state, const Lardon3DTask *task,
|
|||
? lardon3d_project_db_record_geometric_verifier_task(
|
||||
state->project_db, &snapshot, task_kind, task_kind_version, &checkpoint,
|
||||
geometric_parameters, now.tv_sec)
|
||||
: campaign_parameters
|
||||
? lardon3d_project_db_record_acquisition_campaign_task(
|
||||
state->project_db, &snapshot, task_kind, task_kind_version, &checkpoint,
|
||||
campaign_parameters, now.tv_sec)
|
||||
: lardon3d_project_db_record_task(state->project_db, &snapshot, task_kind,
|
||||
task_kind_version, &checkpoint, now.tv_sec);
|
||||
if (recorded == LARDON3D_PROJECT_DB_BUSY) {
|
||||
|
|
@ -756,7 +761,7 @@ checkpoint_task_internal(Lardon3DAppState *state, const Lardon3DTask *task,
|
|||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_task(Lardon3DAppState *state,
|
||||
const Lardon3DTask *task) {
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult
|
||||
|
|
@ -766,7 +771,15 @@ lardon3d_project_checkpoint_image_import_task(Lardon3DAppState *state, const Lar
|
|||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(
|
||||
state, task, source_path, scanset_id, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
state, task, source_path, scanset_id, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_acquisition_campaign_task(
|
||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *parameters) {
|
||||
if (!parameters) return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
parameters);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_task(
|
||||
|
|
@ -775,14 +788,16 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_
|
|||
if (!parameters) {
|
||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(state, task, NULL, 0, parameters, NULL, NULL, NULL, NULL, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, parameters, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_sift_extract_task(
|
||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||
const Lardon3DProjectDbSiftExtractTask *parameters) {
|
||||
if (!parameters) return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, parameters, NULL, NULL, NULL, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, parameters, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_visual_index_update_task(
|
||||
|
|
@ -791,7 +806,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_visual_index_upd
|
|||
if (!parameters) {
|
||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, parameters, NULL, NULL, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, parameters, NULL, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_candidate_pair_generate_task(
|
||||
|
|
@ -800,7 +816,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_candidate_pair_g
|
|||
if (!parameters) {
|
||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, parameters, NULL, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, parameters, NULL, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_matcher_task(
|
||||
|
|
@ -809,7 +826,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_matcher_task(
|
|||
if (!parameters) {
|
||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, parameters, NULL);
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, parameters, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_geometric_verifier_task(
|
||||
|
|
@ -819,7 +837,7 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_geometric_verifi
|
|||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||
}
|
||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL,
|
||||
parameters);
|
||||
parameters, NULL);
|
||||
}
|
||||
|
||||
static bool coherent_recovery(const Lardon3DProjectDbTask *database_task,
|
||||
|
|
|
|||
231
src/project_db.c
231
src/project_db.c
|
|
@ -607,6 +607,19 @@ static const char schema_capture_provenance_v19[] =
|
|||
"created_at INTEGER NOT NULL CHECK(created_at>=0),"
|
||||
"CHECK(parent_asset_id!=child_asset_id));";
|
||||
|
||||
static const char schema_acquisition_campaign_v20[] =
|
||||
"CREATE TABLE IF NOT EXISTS acquisition_campaign_tasks("
|
||||
"task_id INTEGER PRIMARY KEY REFERENCES tasks(task_id) ON DELETE CASCADE,"
|
||||
"scanset_id INTEGER NOT NULL REFERENCES scansets(scanset_id),"
|
||||
"next_group_id INTEGER NOT NULL CHECK(next_group_id>=0 AND next_group_id<=4294967295),"
|
||||
"group_count INTEGER NOT NULL CHECK(group_count>0 AND group_count<=4096),"
|
||||
"request BLOB NOT NULL CHECK(length(request)>0));"
|
||||
"CREATE TABLE IF NOT EXISTS acquisition_campaign_captures("
|
||||
"task_id INTEGER NOT NULL REFERENCES acquisition_campaign_tasks(task_id) ON DELETE CASCADE,"
|
||||
"group_id INTEGER NOT NULL CHECK(group_id>=0 AND group_id<=4294967295),"
|
||||
"capture_id INTEGER NOT NULL REFERENCES captures(capture_id),"
|
||||
"PRIMARY KEY(task_id,group_id),UNIQUE(task_id,capture_id));";
|
||||
|
||||
static void copy_error(char destination[LARDON3D_PROJECT_DB_ERROR_CAPACITY], const char *text) {
|
||||
if (destination) {
|
||||
(void)snprintf(destination, LARDON3D_PROJECT_DB_ERROR_CAPACITY, "%s", text ? text : "");
|
||||
|
|
@ -1093,6 +1106,22 @@ static Lardon3DProjectDbResult migrate(Lardon3DProjectDb *database, unsigned int
|
|||
"finish schema v19 migration");
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && from_version < 20) {
|
||||
result = execute(database, schema_acquisition_campaign_v20,
|
||||
"migrate acquisition campaign task v19 to v20");
|
||||
#ifdef LARDON3D_PROJECT_DB_TESTING
|
||||
if (result == LARDON3D_PROJECT_DB_OK &&
|
||||
getenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V20")) {
|
||||
result = execute(database, "INSERT INTO missing_v20_test_table VALUES(1)",
|
||||
"forced migration v20 failure");
|
||||
}
|
||||
#endif
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database,
|
||||
"UPDATE metadata SET value=20 WHERE key='schema_version' AND value=19",
|
||||
"finish schema v20 migration");
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = execute(database, "COMMIT", "commit migration");
|
||||
}
|
||||
|
|
@ -1228,7 +1257,9 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
|||
"capture_images",
|
||||
"capture_assets",
|
||||
"capture_selections",
|
||||
"asset_derivations"};
|
||||
"asset_derivations",
|
||||
"acquisition_campaign_tasks",
|
||||
"acquisition_campaign_captures"};
|
||||
for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
|
||||
result == LARDON3D_PROJECT_DB_OK;
|
||||
++index) {
|
||||
|
|
@ -1452,6 +1483,7 @@ record_task_internal(Lardon3DProjectDb *database, const Lardon3DTaskDurableSnaps
|
|||
const Lardon3DProjectDbMatcherTask *matcher,
|
||||
const Lardon3DProjectDbGeometricVerifierTask *geometric_verifier,
|
||||
const Lardon3DProjectDbSparseSfmTask *sparse_sfm,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *campaign,
|
||||
int64_t updated_at) {
|
||||
bool typed = task_kind != NULL;
|
||||
if (!database || !valid_durable_task(snapshot, updated_at) ||
|
||||
|
|
@ -1518,6 +1550,11 @@ record_task_internal(Lardon3DProjectDb *database, const Lardon3DTaskDurableSnaps
|
|||
!valid_task_id(sparse_sfm->track_set_id) ||
|
||||
!valid_task_id(sparse_sfm->calibration_scope_id) || sparse_sfm->sfm_kind != 1 ||
|
||||
sparse_sfm->sfm_version != 1 || !valid_sparse_sfm_parameters(&sparse_sfm->parameters))) ||
|
||||
(campaign && (!valid_task_id(campaign->task_id) || campaign->task_id != snapshot->id ||
|
||||
!valid_task_id(campaign->scanset_id) || campaign->group_count == 0 ||
|
||||
campaign->group_count > 4096 ||
|
||||
campaign->next_group_id > campaign->group_count || !campaign->request ||
|
||||
campaign->request_size == 0 || campaign->request_size > INT_MAX)) ||
|
||||
(checkpoint && !valid_checkpoint(checkpoint))) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
|
|
@ -1582,6 +1619,26 @@ record_task_internal(Lardon3DProjectDb *database, const Lardon3DTaskDurableSnaps
|
|||
}
|
||||
#endif
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && campaign) {
|
||||
result = prepare(database,
|
||||
"INSERT INTO acquisition_campaign_tasks(task_id,scanset_id,next_group_id,group_count,"
|
||||
"request) VALUES(?1,?2,?3,?4,?5) ON CONFLICT(task_id) DO UPDATE SET "
|
||||
"next_group_id=excluded.next_group_id WHERE scanset_id=excluded.scanset_id AND "
|
||||
"group_count=excluded.group_count AND request=excluded.request", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)campaign->task_id);
|
||||
sqlite3_bind_int64(statement, 2, (sqlite3_int64)campaign->scanset_id);
|
||||
sqlite3_bind_int64(statement, 3, campaign->next_group_id);
|
||||
sqlite3_bind_int64(statement, 4, campaign->group_count);
|
||||
sqlite3_bind_blob(statement, 5, campaign->request, (int)campaign->request_size,
|
||||
SQLITE_TRANSIENT);
|
||||
result = step_done(database, statement, "upsert campaign task");
|
||||
if (result == LARDON3D_PROJECT_DB_OK && sqlite3_changes(database->connection) != 1) {
|
||||
copy_error(database->error, "Payload de campagne immuable.");
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result =
|
||||
prepare(database,
|
||||
|
|
@ -1916,7 +1973,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_task(
|
|||
Lardon3DProjectDb *database, const Lardon3DTaskDurableSnapshot *snapshot, const char *task_kind,
|
||||
uint32_t task_kind_version, const Lardon3DProjectDbCheckpoint *checkpoint, int64_t updated_at) {
|
||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint, NULL, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_image_import_task(
|
||||
|
|
@ -1928,7 +1985,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_image_import_task(
|
|||
}
|
||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint,
|
||||
source_path, scanset_id, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL, updated_at);
|
||||
NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_feature_extract_task(
|
||||
|
|
@ -1939,7 +1996,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_feature_extract_task(
|
|||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint, NULL, 0,
|
||||
parameters, NULL, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
parameters, NULL, NULL, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_sift_extract_task(
|
||||
|
|
@ -1949,7 +2006,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_sift_extract_task(
|
|||
const Lardon3DProjectDbSiftExtractTask *parameters, int64_t updated_at) {
|
||||
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint, NULL, 0,
|
||||
NULL, parameters, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
NULL, parameters, NULL, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
static bool read_task(sqlite3_stmt *statement, Lardon3DProjectDbTask *task) {
|
||||
|
|
@ -2179,6 +2236,158 @@ lardon3d_project_db_load_image_import(Lardon3DProjectDb *database, uint64_t task
|
|||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_record_acquisition_campaign_task(
|
||||
Lardon3DProjectDb *database, const Lardon3DTaskDurableSnapshot *snapshot,
|
||||
const char *task_kind, uint32_t task_kind_version,
|
||||
const Lardon3DProjectDbCheckpoint *checkpoint,
|
||||
const Lardon3DProjectDbAcquisitionCampaignTask *parameters, int64_t updated_at) {
|
||||
if (!database || !snapshot || !parameters || parameters->task_id != snapshot->id ||
|
||||
!valid_task_id(parameters->scanset_id) || parameters->group_count == 0 ||
|
||||
parameters->group_count > 4096 || parameters->next_group_id > parameters->group_count ||
|
||||
!parameters->request || parameters->request_size == 0 || parameters->request_size > INT_MAX) {
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint,
|
||||
NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, parameters,
|
||||
updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_acquisition_campaign_task(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, unsigned char *request,
|
||||
size_t request_capacity, Lardon3DProjectDbAcquisitionCampaignTask *parameters) {
|
||||
if (!database || !valid_task_id(task_id) || !request || request_capacity == 0 || !parameters)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
memset(parameters, 0, sizeof(*parameters));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(database,
|
||||
"SELECT scanset_id,next_group_id,group_count,request FROM acquisition_campaign_tasks "
|
||||
"WHERE task_id=?1", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)task_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
else if (code != SQLITE_ROW) result = sqlite_result(database, code, "load campaign task");
|
||||
else {
|
||||
int bytes = sqlite3_column_bytes(statement, 3);
|
||||
const void *blob = sqlite3_column_blob(statement, 3);
|
||||
if (bytes <= 0 || (size_t)bytes > request_capacity || !blob) {
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
} else {
|
||||
parameters->task_id = task_id;
|
||||
parameters->scanset_id = (uint64_t)sqlite3_column_int64(statement, 0);
|
||||
parameters->next_group_id = (uint32_t)sqlite3_column_int64(statement, 1);
|
||||
parameters->group_count = (uint32_t)sqlite3_column_int64(statement, 2);
|
||||
memcpy(request, blob, (size_t)bytes);
|
||||
parameters->request = request;
|
||||
parameters->request_size = (size_t)bytes;
|
||||
}
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, uint32_t group_id,
|
||||
uint64_t capture_id, uint32_t next_group_id) {
|
||||
if (!database || !valid_task_id(task_id) || !valid_task_id(capture_id) ||
|
||||
group_id == 0 || next_group_id != group_id) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
Lardon3DProjectDbResult result = execute(database, "BEGIN IMMEDIATE", "begin capture retention");
|
||||
sqlite3_stmt *statement = NULL;
|
||||
uint32_t cursor = 0;
|
||||
uint32_t group_count = 0;
|
||||
uint64_t retained_capture_id = 0;
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
result = prepare(database,
|
||||
"SELECT t.next_group_id,t.group_count,COALESCE(m.capture_id,0),"
|
||||
"EXISTS(SELECT 1 FROM captures c WHERE c.capture_id=?3 AND "
|
||||
"c.scanset_id=t.scanset_id) FROM acquisition_campaign_tasks t LEFT JOIN "
|
||||
"acquisition_campaign_captures m ON m.task_id=t.task_id AND m.group_id=?2 "
|
||||
"WHERE t.task_id=?1", &statement);
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)task_id);
|
||||
sqlite3_bind_int64(statement, 2, group_id);
|
||||
sqlite3_bind_int64(statement, 3, (sqlite3_int64)capture_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
else if (code != SQLITE_ROW) result = sqlite_result(database, code, "validate capture retention");
|
||||
else {
|
||||
cursor = (uint32_t)sqlite3_column_int64(statement, 0);
|
||||
group_count = (uint32_t)sqlite3_column_int64(statement, 1);
|
||||
retained_capture_id = (uint64_t)sqlite3_column_int64(statement, 2);
|
||||
bool matching_scanset = sqlite3_column_int(statement, 3) == 1;
|
||||
bool new_mapping = cursor + 1u == group_id && retained_capture_id == 0;
|
||||
bool exact_retry = cursor == next_group_id && retained_capture_id == capture_id;
|
||||
if (group_id > group_count || !matching_scanset || (!new_mapping && !exact_retry))
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
statement = NULL;
|
||||
if (result == LARDON3D_PROJECT_DB_OK && retained_capture_id == 0)
|
||||
result = prepare(database,
|
||||
"INSERT INTO acquisition_campaign_captures(task_id,group_id,capture_id) VALUES(?1,?2,?3)",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK && retained_capture_id == 0) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)task_id);
|
||||
sqlite3_bind_int64(statement, 2, group_id);
|
||||
sqlite3_bind_int64(statement, 3, (sqlite3_int64)capture_id);
|
||||
result = step_done(database, statement, "retain campaign capture");
|
||||
if (result == LARDON3D_PROJECT_DB_OK && sqlite3_changes(database->connection) != 1)
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK && cursor + 1u == group_id) {
|
||||
result = prepare(database,
|
||||
"UPDATE acquisition_campaign_tasks SET next_group_id=?2 WHERE task_id=?1 AND "
|
||||
"next_group_id=?3 AND group_count>=?2", &statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)task_id);
|
||||
sqlite3_bind_int64(statement, 2, next_group_id);
|
||||
sqlite3_bind_int64(statement, 3, (sqlite3_int64)group_id - 1);
|
||||
result = step_done(database, statement, "advance campaign cursor");
|
||||
if (result == LARDON3D_PROJECT_DB_OK && sqlite3_changes(database->connection) != 1)
|
||||
result = LARDON3D_PROJECT_DB_CONSTRAINT;
|
||||
}
|
||||
}
|
||||
if (result == LARDON3D_PROJECT_DB_OK)
|
||||
result = execute(database, "COMMIT", "commit capture retention");
|
||||
if (result != LARDON3D_PROJECT_DB_OK)
|
||||
(void)execute(database, "ROLLBACK", "rollback capture retention");
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_acquisition_campaign_capture(
|
||||
Lardon3DProjectDb *database, uint64_t task_id, uint32_t group_id,
|
||||
Lardon3DProjectDbAcquisitionCampaignCapture *capture) {
|
||||
if (!database || !valid_task_id(task_id) || !capture)
|
||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
memset(capture, 0, sizeof(*capture));
|
||||
(void)pthread_mutex_lock(&database->mutex);
|
||||
sqlite3_stmt *statement = NULL;
|
||||
Lardon3DProjectDbResult result = prepare(database,
|
||||
"SELECT capture_id FROM acquisition_campaign_captures WHERE task_id=?1 AND group_id=?2",
|
||||
&statement);
|
||||
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||
sqlite3_bind_int64(statement, 1, (sqlite3_int64)task_id);
|
||||
sqlite3_bind_int64(statement, 2, group_id);
|
||||
int code = sqlite3_step(statement);
|
||||
if (code == SQLITE_DONE) result = LARDON3D_PROJECT_DB_NOT_FOUND;
|
||||
else if (code != SQLITE_ROW) result = sqlite_result(database, code, "load retained capture");
|
||||
else {
|
||||
capture->group_id = group_id;
|
||||
capture->capture_id = (uint64_t)sqlite3_column_int64(statement, 0);
|
||||
}
|
||||
}
|
||||
sqlite3_finalize(statement);
|
||||
(void)pthread_mutex_unlock(&database->mutex);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool valid_catalog_id(uint64_t value) { return value > 0 && value <= INT64_MAX; }
|
||||
|
||||
static bool valid_original_name(const char *name) {
|
||||
|
|
@ -4764,7 +4973,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_visual_index_update_task(
|
|||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
||||
NULL, parameters, NULL, NULL, NULL, NULL, updated_at);
|
||||
NULL, parameters, NULL, NULL, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_visual_index_update_task(
|
||||
|
|
@ -4811,7 +5020,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_candidate_pair_generate_task(
|
|||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
||||
NULL, NULL, parameters, NULL, NULL, NULL, updated_at);
|
||||
NULL, NULL, parameters, NULL, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_candidate_pair_generate_task(
|
||||
|
|
@ -4867,7 +5076,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_matcher_task(
|
|||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, parameters, NULL, NULL, updated_at);
|
||||
NULL, NULL, NULL, parameters, NULL, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_matcher_task(
|
||||
|
|
@ -4925,7 +5134,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_geometric_verifier_task(
|
|||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
}
|
||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
||||
NULL, NULL, NULL, NULL, parameters, NULL, updated_at);
|
||||
NULL, NULL, NULL, NULL, parameters, NULL, NULL, updated_at);
|
||||
}
|
||||
|
||||
Lardon3DProjectDbResult lardon3d_project_db_load_geometric_verifier_task(
|
||||
|
|
@ -4998,7 +5207,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_track_builder_task(
|
|||
}
|
||||
Lardon3DProjectDbResult result = record_task_internal(
|
||||
db, snapshot, kind, version, checkpoint, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
||||
updated_at);
|
||||
NULL, updated_at);
|
||||
if (result != LARDON3D_PROJECT_DB_OK) return result;
|
||||
(void)pthread_mutex_lock(&db->mutex);
|
||||
result = execute(db, "BEGIN IMMEDIATE", "begin track builder task");
|
||||
|
|
@ -5109,7 +5318,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_sparse_sfm_task(
|
|||
const Lardon3DProjectDbSparseSfmTask *parameters, int64_t updated_at) {
|
||||
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||
return record_task_internal(database, snapshot, kind, version, checkpoint, NULL, 0, NULL, NULL,
|
||||
NULL, NULL, NULL, NULL, parameters, updated_at);
|
||||
NULL, NULL, NULL, NULL, parameters, NULL, updated_at);
|
||||
}
|
||||
|
||||
static bool read_u64_blob(sqlite3_stmt *statement, int column, uint64_t *value) {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
#include <lardon3d/candidate_pair_task.h>
|
||||
#ifdef LARDON3D_ACQUISITION_CAMPAIGN_TASK_AVAILABLE
|
||||
#include <lardon3d/acquisition_campaign_task.h>
|
||||
#endif
|
||||
#include <lardon3d/feature_task.h>
|
||||
#include <lardon3d/geometric_verifier_task.h>
|
||||
#include <lardon3d/import_task.h>
|
||||
|
|
@ -18,6 +21,13 @@
|
|||
|
||||
const Lardon3DTaskKindRegistry *lardon3d_task_kind_registry_production(void) {
|
||||
static const Lardon3DTaskKindDescriptor descriptors[] = {
|
||||
#ifdef LARDON3D_ACQUISITION_CAMPAIGN_TASK_AVAILABLE
|
||||
{
|
||||
.kind = LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND,
|
||||
.kind_version = LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND_VERSION,
|
||||
.reconstruct = lardon3d_acquisition_campaign_task_reconstruct,
|
||||
},
|
||||
#endif
|
||||
{
|
||||
.kind = LARDON3D_IMAGE_IMPORT_TASK_KIND,
|
||||
.kind_version = LARDON3D_IMAGE_IMPORT_TASK_KIND_VERSION,
|
||||
|
|
|
|||
187
tests/test_acquisition_campaign_task.cpp
Normal file
187
tests/test_acquisition_campaign_task.cpp
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <vector>
|
||||
|
||||
extern "C" {
|
||||
#include <lardon3d/acquisition_campaign_task.h>
|
||||
#include <lardon3d/project_db.h>
|
||||
}
|
||||
|
||||
#define CHECK(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
std::fprintf(stderr, "failure line %d: %s\n", __LINE__, #x); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
extern "C" const Lardon3DTaskKindRegistry *
|
||||
lardon3d_task_kind_registry_production(void) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Lardon3DAcquisitionCampaignSource sources[2]{};
|
||||
std::snprintf(sources[0].path, sizeof(sources[0].path), "/input/a.arw");
|
||||
std::snprintf(sources[1].path, sizeof(sources[1].path), "/input/a.jpg");
|
||||
sources[0].source_kind = sources[0].metadata.source_kind =
|
||||
LARDON3D_ACQUISITION_SOURCE_RAW;
|
||||
sources[1].source_kind = sources[1].metadata.source_kind =
|
||||
LARDON3D_ACQUISITION_SOURCE_JPEG;
|
||||
for (auto &source : sources) {
|
||||
source.metadata_result = LARDON3D_ACQUISITION_OK;
|
||||
source.metadata.policy_version =
|
||||
LARDON3D_ACQUISITION_PAIRING_POLICY_VERSION;
|
||||
}
|
||||
Lardon3DAcquisitionCampaignConfirmation confirmation{};
|
||||
confirmation.source_count = 2;
|
||||
confirmation.source_indices[0] = 0;
|
||||
confirmation.source_indices[1] = 1;
|
||||
Lardon3DAcquisitionCampaignTaskRequest input{};
|
||||
input.sources = sources;
|
||||
input.source_count = 2;
|
||||
input.confirmations = &confirmation;
|
||||
input.confirmation_count = 1;
|
||||
input.ingest_options.representation = LARDON3D_ACQUISITION_SELECT_DEVELOP_RAW;
|
||||
input.ingest_options.select_representation = 1;
|
||||
input.ingest_options.imported_at = 123;
|
||||
input.ingest_options.max_source_bytes = 456;
|
||||
|
||||
size_t size = 0;
|
||||
CHECK(
|
||||
lardon3d_acquisition_campaign_request_encode(&input, nullptr, 0, &size));
|
||||
CHECK(size > 32);
|
||||
std::vector<unsigned char> encoded(size);
|
||||
CHECK(lardon3d_acquisition_campaign_request_encode(&input, encoded.data(),
|
||||
encoded.size(), &size));
|
||||
Lardon3DAcquisitionCampaignSource decoded_sources[2]{};
|
||||
Lardon3DAcquisitionCampaignConfirmation decoded_confirmations[2]{};
|
||||
Lardon3DAcquisitionCampaignTaskRequest decoded{};
|
||||
CHECK(lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), decoded_sources, 2, decoded_confirmations,
|
||||
2, &decoded));
|
||||
CHECK(decoded.source_count == 2 && decoded.confirmation_count == 1);
|
||||
CHECK(decoded_confirmations[0].source_count == 2);
|
||||
CHECK(decoded.ingest_options.representation ==
|
||||
LARDON3D_ACQUISITION_SELECT_DEVELOP_RAW);
|
||||
CHECK(decoded.ingest_options.select_representation == 1);
|
||||
CHECK(decoded.ingest_options.imported_at == 123 &&
|
||||
decoded.ingest_options.max_source_bytes == 456);
|
||||
CHECK(std::strcmp(decoded_sources[0].path, "/input/a.arw") == 0);
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), nullptr, 2, decoded_confirmations, 2,
|
||||
&decoded));
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), decoded_sources, 2, nullptr, 2,
|
||||
&decoded));
|
||||
|
||||
constexpr size_t imported_at_offset = 8u + 5u * sizeof(uint32_t);
|
||||
for (size_t i = 0; i < sizeof(uint64_t); ++i)
|
||||
encoded[imported_at_offset + i] = 0xffu;
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), decoded_sources, 2, decoded_confirmations,
|
||||
2, &decoded));
|
||||
for (size_t i = 0; i < sizeof(uint64_t); ++i)
|
||||
encoded[imported_at_offset + i] =
|
||||
static_cast<unsigned char>(uint64_t(123) >> (8u * i));
|
||||
|
||||
input.ingest_options.imported_at = -1;
|
||||
CHECK(!lardon3d_acquisition_campaign_request_encode(&input, nullptr, 0,
|
||||
&size));
|
||||
input.ingest_options.imported_at = 123;
|
||||
input.ingest_options.max_source_bytes = 0;
|
||||
CHECK(!lardon3d_acquisition_campaign_request_encode(&input, nullptr, 0,
|
||||
&size));
|
||||
input.ingest_options.max_source_bytes = 456;
|
||||
|
||||
encoded[8] = 2;
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), decoded_sources, 2, decoded_confirmations,
|
||||
2, &decoded));
|
||||
encoded[8] = 1;
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size() - 1, decoded_sources, 2,
|
||||
decoded_confirmations, 2, &decoded));
|
||||
CHECK(!lardon3d_acquisition_campaign_request_decode(
|
||||
encoded.data(), encoded.size(), decoded_sources, 1, decoded_confirmations,
|
||||
2, &decoded));
|
||||
|
||||
char database_path[] = "/tmp/lardon3d-campaign-task-XXXXXX";
|
||||
int descriptor = mkstemp(database_path);
|
||||
CHECK(descriptor >= 0 && close(descriptor) == 0 &&
|
||||
unlink(database_path) == 0);
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]{};
|
||||
Lardon3DProjectDb *database = nullptr;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DProjectDbScanSet target{}, other{};
|
||||
CHECK(lardon3d_project_db_create_scanset(database, "target", &target) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_scanset(database, "other", &other) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
Lardon3DTaskDurableSnapshot snapshot{};
|
||||
snapshot.id = 1;
|
||||
std::snprintf(snapshot.name, sizeof(snapshot.name), "campaign");
|
||||
snapshot.saved_state = snapshot.recovery_state = TASK_PENDING;
|
||||
Lardon3DProjectDbAcquisitionCampaignTask durable{
|
||||
1, target.scanset_id, 0, 2, encoded.data(), encoded.size()};
|
||||
CHECK(lardon3d_project_db_record_acquisition_campaign_task(
|
||||
database, &snapshot, LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND,
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND_VERSION, nullptr, &durable,
|
||||
1) == LARDON3D_PROJECT_DB_OK);
|
||||
std::vector<unsigned char> changed = encoded;
|
||||
changed.back() ^= 1u;
|
||||
snapshot.progress = 50;
|
||||
durable.request = changed.data();
|
||||
CHECK(lardon3d_project_db_record_acquisition_campaign_task(
|
||||
database, &snapshot, LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND,
|
||||
LARDON3D_ACQUISITION_CAMPAIGN_TASK_KIND_VERSION, nullptr, &durable,
|
||||
2) == LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
Lardon3DProjectDbTask generic{};
|
||||
CHECK(lardon3d_project_db_load_task(database, 1, &generic) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
generic.progress == 0);
|
||||
snapshot.progress = 0;
|
||||
durable.request = encoded.data();
|
||||
Lardon3DProjectDbCapture first{}, wrong{}, second{};
|
||||
CHECK(lardon3d_project_db_create_capture(database, target.scanset_id, 1,
|
||||
&first) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_capture(database, other.scanset_id, 1,
|
||||
&wrong) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_create_capture(database, target.scanset_id, 1,
|
||||
&second) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
database, 1, 1, wrong.capture_id, 1) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
CHECK(lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
database, 1, 2, second.capture_id, 2) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
CHECK(lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
database, 1, 1, first.capture_id, 1) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
database, 1, 1, first.capture_id, 1) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_retain_acquisition_campaign_capture(
|
||||
database, 1, 1, second.capture_id, 1) ==
|
||||
LARDON3D_PROJECT_DB_CONSTRAINT);
|
||||
std::vector<unsigned char> loaded(encoded.size());
|
||||
Lardon3DProjectDbAcquisitionCampaignTask loaded_task{};
|
||||
CHECK(lardon3d_project_db_load_acquisition_campaign_task(
|
||||
database, 1, loaded.data(), loaded.size(), &loaded_task) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(loaded_task.next_group_id == 1 && loaded_task.group_count == 2 &&
|
||||
loaded_task.request_size == encoded.size() &&
|
||||
std::memcmp(loaded.data(), encoded.data(), encoded.size()) == 0);
|
||||
std::vector<char> overlong_project_path(LARDON3D_APP_STATE_PATH_CAPACITY + 1,
|
||||
'x');
|
||||
overlong_project_path.back() = '\0';
|
||||
Lardon3DTaskReconstructionContext reconstruction{
|
||||
overlong_project_path.data(), database, nullptr, nullptr};
|
||||
Lardon3DTaskKindBinding binding{};
|
||||
CHECK(!lardon3d_acquisition_campaign_task_reconstruct(
|
||||
&snapshot, &reconstruction, &binding));
|
||||
lardon3d_project_db_close(database);
|
||||
CHECK(unlink(database_path) == 0);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -202,7 +202,7 @@ static bool test_model_api(const char *path) {
|
|||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
Parents parents;
|
||||
CHECK(create_parents(database, &parents));
|
||||
|
||||
|
|
@ -486,7 +486,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v11_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
Parents parents;
|
||||
CHECK(create_parents(database, &parents));
|
||||
unsigned char fingerprint[32] = {0x91};
|
||||
|
|
@ -501,7 +501,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
migrated_result.geometric_verification_result_id;
|
||||
lardon3d_project_db_close(database);
|
||||
CHECK(query_integer(
|
||||
v11_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v11_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
CHECK(
|
||||
query_integer(v11_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='index' AND "
|
||||
|
|
@ -530,7 +530,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -369,7 +369,7 @@ static bool run_task_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
CHECK(remove_tree(root));
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ static bool run_test(void) {
|
|||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 20);
|
||||
|
||||
Lardon3DProjectDbScanSet scanset;
|
||||
CHECK(lardon3d_project_db_create_scanset(database, "Match-test", &scanset) ==
|
||||
|
|
@ -501,7 +501,7 @@ static bool run_test(void) {
|
|||
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
|
||||
/* Verify persistence: load previously created results */
|
||||
CHECK(lardon3d_project_db_load_match_result(database, first_id, &loaded) ==
|
||||
|
|
@ -544,11 +544,11 @@ static bool run_test(void) {
|
|||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 9));
|
||||
CHECK(lardon3d_project_db_open(v9_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
CHECK(
|
||||
query_integer(v9_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -576,7 +576,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v10_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -373,7 +373,7 @@ static bool run_test(void) {
|
|||
"name='matcher_tasks'",
|
||||
0));
|
||||
CHECK(reopen_runtime(&fixture));
|
||||
CHECK(lardon3d_project_db_schema_version(fixture.state.project_db) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(fixture.state.project_db) == 20);
|
||||
CHECK(
|
||||
query_integer(database_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ static bool create_future_database(const char *path) {
|
|||
sqlite3_exec(
|
||||
connection,
|
||||
"CREATE TABLE metadata(key TEXT PRIMARY KEY,value INTEGER NOT NULL);"
|
||||
"INSERT INTO metadata VALUES('schema_version',20);",
|
||||
"INSERT INTO metadata VALUES('schema_version',21);",
|
||||
NULL, NULL, NULL) == SQLITE_OK;
|
||||
return sqlite3_close(connection) == SQLITE_OK && ok;
|
||||
}
|
||||
|
|
@ -940,7 +940,7 @@ static bool run_test(void) {
|
|||
Lardon3DProjectDb *database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(database && lardon3d_project_db_schema_version(database) == 20);
|
||||
bool legacy_pending = true;
|
||||
CHECK(lardon3d_project_db_legacy_catalog_pending(database, &legacy_pending) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
|
|
@ -1499,7 +1499,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(query_integer(database_path,
|
||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||
19));
|
||||
20));
|
||||
CHECK(query_integer(database_path,
|
||||
"SELECT count(*) FROM tasks WHERE task_id=1", 1));
|
||||
|
||||
|
|
@ -1521,12 +1521,13 @@ static bool run_test(void) {
|
|||
"created_at) VALUES(1,1,1,1,1,zeroblob(32),1,2,1,0,0,1);"
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE acquisition_campaign_captures;DROP TABLE acquisition_campaign_tasks;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
||||
CHECK(lardon3d_project_db_open(v17_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(v17_path,
|
||||
|
|
@ -1550,6 +1551,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(execute_test_sql(
|
||||
failed_v19_path,
|
||||
"DROP TABLE acquisition_campaign_captures;DROP TABLE acquisition_campaign_tasks;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=18 WHERE key='schema_version';"));
|
||||
|
|
@ -1564,13 +1566,14 @@ static bool run_test(void) {
|
|||
"name='captures'", 0));
|
||||
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(execute_test_sql(
|
||||
failed_v18_path,
|
||||
"DROP TABLE incremental_reconstruction_tasks;"
|
||||
"DROP TABLE incremental_reconstructions;"
|
||||
"DROP TABLE acquisition_campaign_captures;DROP TABLE acquisition_campaign_tasks;"
|
||||
"DROP TABLE asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
||||
|
|
@ -1615,7 +1618,7 @@ static bool run_test(void) {
|
|||
CHECK(create_v1_database(legacy_path));
|
||||
CHECK(lardon3d_project_db_open(legacy_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
CHECK(lardon3d_project_db_get_project(database, &loaded_project) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
strcmp(loaded_project.stable_id, "legacy-project") == 0);
|
||||
|
|
@ -1630,7 +1633,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(query_integer(legacy_path,
|
||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||
19));
|
||||
20));
|
||||
|
||||
CHECK(create_v1_database(failed_migration_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V2", "1", 1) == 0);
|
||||
|
|
@ -1661,7 +1664,7 @@ static bool run_test(void) {
|
|||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v2_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v2_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
|
||||
CHECK(create_v2_database(failed_v3_migration_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V3", "1", 1) == 0);
|
||||
|
|
@ -1695,7 +1698,7 @@ static bool run_test(void) {
|
|||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v3_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v3_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
|
||||
CHECK(create_v3_database(failed_v4_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V4", "1", 1) == 0);
|
||||
|
|
@ -1717,7 +1720,7 @@ static bool run_test(void) {
|
|||
fprintf(stderr, "Migration v4 (%d): %s\n", (int)v4_result, error);
|
||||
}
|
||||
CHECK(v4_result == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
CHECK(lardon3d_project_db_load_task(database, 9, &task) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_load_artifact(database, "legacy-artifact",
|
||||
|
|
@ -1772,7 +1775,7 @@ static bool run_test(void) {
|
|||
error);
|
||||
}
|
||||
CHECK(retry_v7 == LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1782,7 +1785,7 @@ static bool run_test(void) {
|
|||
5));
|
||||
CHECK(lardon3d_project_db_open(direct_v5_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1791,11 +1794,11 @@ static bool run_test(void) {
|
|||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 7));
|
||||
CHECK(lardon3d_project_db_open(v8_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
|
||||
CHECK(create_v7_database(failed_v8_path));
|
||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V8", "1", 1) == 0);
|
||||
|
|
@ -1812,7 +1815,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v8_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1831,11 +1834,11 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v10_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v10_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v10_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
CHECK(
|
||||
query_integer(v10_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -1862,7 +1865,7 @@ static bool run_test(void) {
|
|||
1));
|
||||
CHECK(lardon3d_project_db_open(failed_v11_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -1876,11 +1879,11 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(v13_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(query_integer(
|
||||
v13_path, "SELECT value FROM metadata WHERE key='schema_version'", 19));
|
||||
v13_path, "SELECT value FROM metadata WHERE key='schema_version'", 20));
|
||||
CHECK(
|
||||
query_integer(v13_path,
|
||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||
|
|
@ -1903,7 +1906,7 @@ static bool run_test(void) {
|
|||
true_v14_path);
|
||||
}
|
||||
CHECK(true_v14_result == LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(
|
||||
|
|
@ -2018,7 +2021,7 @@ static bool run_test(void) {
|
|||
if (true_v15_result != LARDON3D_PROJECT_DB_OK)
|
||||
fprintf(stderr, "true v15 upgrade: %d %s\n", true_v15_result, error);
|
||||
CHECK(true_v15_result == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
Lardon3DProjectDbProject migrated_project;
|
||||
CHECK(lardon3d_project_db_get_project(database, &migrated_project) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
|
|
@ -2064,7 +2067,7 @@ static bool run_test(void) {
|
|||
database = NULL;
|
||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
CHECK(schema_compare(database_path, true_v15_path, true));
|
||||
|
|
@ -2099,7 +2102,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(true_v15_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -2118,7 +2121,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v14_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
@ -2137,7 +2140,7 @@ static bool run_test(void) {
|
|||
0));
|
||||
CHECK(lardon3d_project_db_open(failed_v15_path, &database, error) ==
|
||||
LARDON3D_PROJECT_DB_OK &&
|
||||
lardon3d_project_db_schema_version(database) == 19);
|
||||
lardon3d_project_db_schema_version(database) == 20);
|
||||
lardon3d_project_db_close(database);
|
||||
database = NULL;
|
||||
|
||||
|
|
|
|||
|
|
@ -123,7 +123,7 @@ static bool run_test(void) {
|
|||
Lardon3DProjectDb *db = NULL;
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||
CHECK(lardon3d_project_db_open(path, &db, error) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(db) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(db) == 20);
|
||||
|
||||
Lardon3DProjectDbScanSet scanset;
|
||||
CHECK(lardon3d_project_db_create_scanset(db, "Sparse model", &scanset) ==
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ int main() {
|
|||
Lardon3DProjectDb *database = nullptr;
|
||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]{};
|
||||
CHECK(lardon3d_project_db_open(path.c_str(), &database, error) == LARDON3D_PROJECT_DB_OK);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
||||
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||
|
||||
sqlite3 *raw = nullptr;
|
||||
CHECK(sqlite3_open(path.c_str(), &raw) == SQLITE_OK);
|
||||
|
|
|
|||
Loading…
Reference in a new issue