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
|
- **Image View** : vues triées et filtrées pour la TUI
|
||||||
- **Task** : moteur de tâches avec pause/reprise, annulation et séquences
|
- **Task** : moteur de tâches avec pause/reprise, annulation et séquences
|
||||||
- **Task Checkpoint v1** : snapshot durable, fichier atomique et reprise sûre
|
- **Task Checkpoint v1** : snapshot durable, fichier atomique et reprise sûre
|
||||||
- **Project Database v19** : fondations v18 préservées, avec Capture / Asset
|
- **Project Database v20** : fondations v19 préservées, avec persistance
|
||||||
Provenance additive
|
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
|
- **Sparse SfM Gates C/D/E** : géométrie calibrée, noyau incrémental et Bundle
|
||||||
Adjustment final par composante, tous PASS / FROZEN
|
Adjustment final par composante, tous PASS / FROZEN
|
||||||
- **Sparse SfM Gate F** : orchestration durable, runtime gouverné et publication
|
- **Sparse SfM Gate F** : orchestration durable, runtime gouverné et publication
|
||||||
|
|
@ -62,15 +66,14 @@ persistante, enrichissable et versionnable.
|
||||||
|
|
||||||
### Prochaine tranche
|
### Prochaine tranche
|
||||||
|
|
||||||
- **Exécution durable de campagne d'acquisition** : confirmations et progression
|
- **Intégration multi-campagne réelle A6000 + S21 Engine Bay** : exécuter les
|
||||||
persistantes, matérialisation S3-E incrémentale, reprise par `capture_id` retenu
|
campagnes persistantes à travers le pipeline scientifique existant. Voir la
|
||||||
et admission par les Task/Scheduler/Governor existants. Voir la
|
|
||||||
[roadmap canonique](docs/roadmap/roadmap.md).
|
[roadmap canonique](docs/roadmap/roadmap.md).
|
||||||
|
|
||||||
### Plus tard / différé
|
### Plus tard / différé
|
||||||
|
|
||||||
- publication durable dense/mesh et scratch SSD externe optionnel gouverné ;
|
- 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
|
- vidéo/keyframes et **Capture Guidance / Live Coverage** : analyse et viewer de
|
||||||
couverture, suggestions de prises de vue puis assistance live, après
|
couverture, suggestions de prises de vue puis assistance live, après
|
||||||
reconstruction mature ;
|
reconstruction mature ;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Base de données projet Lardon3D
|
# 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
|
**PASS / FROZEN.** La migration transactionnelle v18→v19
|
||||||
ajoute seulement une fondation de catalogue : `captures`, `capture_images`,
|
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
|
d'intégration couvre l'adaptateur, sa matérialisation et son retry ; aucune
|
||||||
mutation de campagne complète n'a été effectuée.
|
mutation de campagne complète n'a été effectuée.
|
||||||
|
|
||||||
Restent hors S3 : identité persistante de campagne ou de Task, exécution par
|
Restent hors S3 : TUI, scrub d'assets et réconciliation des orphelins, ainsi
|
||||||
scheduler/Governor, traitement de campagne complet, TUI, scrub d'assets et
|
que vidéo et reconstruction aval lorsqu'ils sont applicables. L'identité
|
||||||
réconciliation des orphelins, ainsi que vidéo et reconstruction aval lorsqu'ils
|
opérationnelle persistante de campagne, son exécution par Task/Scheduler/Governor
|
||||||
sont applicables.
|
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
|
### 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
|
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é.
|
effectivement persistée. Aucun placeholder ni table diagnostique n'est ajouté.
|
||||||
|
|
||||||
> Version courante : **v19**. La migration transactionnelle v18→v19 ajoute la
|
> Version courante : **v20**. La migration transactionnelle additive v19→v20
|
||||||
> fondation Capture/Asset Provenance décrite ci-dessus sans modifier les tables
|
> 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
|
> scientifiques historiques. La migration transactionnelle v17→v18 ajoute le
|
||||||
> discriminateur générique nullable et les deux tables H minimales décrites
|
> discriminateur générique nullable et les deux tables H minimales décrites
|
||||||
> ci-dessus. La migration v16→v17 ajoute le
|
> ci-dessus. La migration v16→v17 ajoute le
|
||||||
|
|
@ -946,10 +995,17 @@ ouvert.
|
||||||
|
|
||||||
## Statut
|
## Statut
|
||||||
|
|
||||||
**PASS / FROZEN** — SQLite système, schéma v19 et migrations séquentielles
|
**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, identité projet, transactions
|
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.
|
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,
|
**IMPLEMENTED** — ouverture/fermeture avec le projet, identité INI/DB cohérente,
|
||||||
publication de checkpoints par le projet et inventaire de reprise validé.
|
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.
|
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.
|
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
|
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
|
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
|
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
|
être confirmées et deviennent `CALLER_EXPLICIT`, jamais `STRONG`. La campagne
|
||||||
complète n'a pas encore été matérialisée.
|
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
|
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
|
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
|
ne sera jamais déduite d'un chemin, SHA, basename, timestamp, métadonnée ou
|
||||||
`image_id`.
|
`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
|
Project DB v20 apporte une migration additive v19→v20. Une tâche de campagne
|
||||||
plan S3 gelé en réutilisant Task, Scheduler et Governor existants :
|
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é ;
|
La requête persiste les confirmations comme `CALLER_EXPLICIT`, jamais comme
|
||||||
2. persistance/rechargement des confirmations, du curseur et des `capture_id` ;
|
inférence `STRONG`. Le plan conserve des IDs de groupe un-based et Project DB
|
||||||
3. matérialisation incrémentale d'un groupe S3-E par unité sûre ;
|
persiste la correspondance `(task_id, group_id) → capture_id`, ainsi que le
|
||||||
4. checkpoint après rétention durable, pause/reprise/annulation aux frontières ;
|
curseur. Chaque séquence admet et matérialise exactement un groupe via S3-E.
|
||||||
5. admission et budgets par l'unique Resource Governor ;
|
Après le retour de S3-E, une transaction conserve le Capture et avance le
|
||||||
6. progression et échecs sans runtime, queue ou persistence parallè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
|
À la réouverture, la registry existante reconstruit la tâche à partir de son
|
||||||
nécessaire. Elle ne peut ni changer les identités S3 ni fusionner des Captures.
|
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 ;
|
1. confirmer explicitement et exécuter les campagnes A6000 et S21 ;
|
||||||
2. matérialiser progressivement environ 953 Captures ;
|
2. matérialiser progressivement leurs Captures et représentations scientifiques
|
||||||
3. produire les représentations scientifiques par lots gouvernés ;
|
par lots gouvernés ;
|
||||||
4. exécuter features, candidats, matching, vérification, tracks et Sparse SfM ;
|
3. exécuter features, candidats, matching, vérification, tracks et Sparse SfM ;
|
||||||
5. évaluer la qualité de la reconstruction sparse ;
|
4. évaluer la qualité de la reconstruction sparse multi-campagne ;
|
||||||
6. exécuter MVS/dense avec budgets et scratch contrôlés ;
|
5. exécuter MVS/dense avec budgets et scratch contrôlés ;
|
||||||
7. publier durablement nuage dense et mesh ;
|
6. publier durablement nuage dense et mesh ;
|
||||||
8. comparer le résultat aux tentatives photogrammétriques antérieures.
|
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
|
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
|
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
|
photographié, mais de guider activement l'opérateur vers les photographies qui
|
||||||
manquent encore pour obtenir une reconstruction fiable. Cette capacité est
|
manquent encore pour obtenir une reconstruction fiable. Cette capacité est
|
||||||
postérieure à une reconstruction suffisamment mature ; elle ne fait pas partie
|
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
|
```text
|
||||||
photographies existantes
|
photographies existantes
|
||||||
|
|
@ -421,10 +432,8 @@ L'ordre demeure sans ambiguïté :
|
||||||
|
|
||||||
```text
|
```text
|
||||||
CURRENT NEXT
|
CURRENT NEXT
|
||||||
exécution durable de campagne (Task / Queue / Scheduler / Governor,
|
intégration réelle multi-campagne A6000 + S21
|
||||||
confirmations durables, progression et reprise)
|
→ pipeline scientifique → dense/mesh → publication
|
||||||
→ INTÉGRATION RÉELLE
|
|
||||||
campagnes A6000 + S21 → pipeline scientifique → dense/mesh → publication
|
|
||||||
→ LATER
|
→ LATER
|
||||||
Coverage Analysis → Coverage Viewer → suggestions de points de vue
|
Coverage Analysis → Coverage Viewer → suggestions de points de vue
|
||||||
→ localisation live → intégration HDMI/USB → Capture Guidance / Live Coverage
|
→ 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
|
- ALIKED tant que provenance modèle, export ONNX et oracle upstream ne sont pas
|
||||||
reproductibles.
|
reproductibles.
|
||||||
|
|
||||||
Ces idées ne doivent pas devancer l'exécution durable de campagne ni créer un
|
Ces idées ne doivent pas devancer l'intégration réelle multi-campagne ni créer
|
||||||
second runtime, Governor ou système de persistance.
|
un second runtime, Governor ou système de persistance.
|
||||||
|
|
||||||
## Principes de séquencement
|
## 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
|
Lardon3DProjectTaskCheckpointResult
|
||||||
lardon3d_project_checkpoint_image_import_task(Lardon3DAppState *state, const Lardon3DTask *task,
|
lardon3d_project_checkpoint_image_import_task(Lardon3DAppState *state, const Lardon3DTask *task,
|
||||||
const char *source_path, uint64_t scanset_id);
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_task(
|
||||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||||
const Lardon3DProjectDbFeatureExtractTask *parameters);
|
const Lardon3DProjectDbFeatureExtractTask *parameters);
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#include <lardon3d/sparse_sfm_incremental.h>
|
#include <lardon3d/sparse_sfm_incremental.h>
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 19,
|
LARDON3D_PROJECT_DB_SCHEMA_VERSION = 20,
|
||||||
LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
|
LARDON3D_PROJECT_DB_ID_CAPACITY = 65,
|
||||||
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
|
LARDON3D_PROJECT_DB_KIND_CAPACITY = 65,
|
||||||
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,
|
LARDON3D_PROJECT_DB_PATH_CAPACITY = 4096,
|
||||||
|
|
@ -100,6 +100,20 @@ typedef struct {
|
||||||
uint64_t scanset_id;
|
uint64_t scanset_id;
|
||||||
} Lardon3DProjectDbImageImport;
|
} 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 {
|
typedef struct {
|
||||||
uint64_t scanset_id;
|
uint64_t scanset_id;
|
||||||
char name[LARDON3D_PROJECT_DB_SCANSET_NAME_CAPACITY];
|
char name[LARDON3D_PROJECT_DB_SCANSET_NAME_CAPACITY];
|
||||||
|
|
@ -570,6 +584,20 @@ Lardon3DProjectDbResult lardon3d_project_db_list_candidate_pairs(
|
||||||
Lardon3DProjectDbResult
|
Lardon3DProjectDbResult
|
||||||
lardon3d_project_db_load_image_import(Lardon3DProjectDb *database, uint64_t task_id,
|
lardon3d_project_db_load_image_import(Lardon3DProjectDb *database, uint64_t task_id,
|
||||||
Lardon3DProjectDbImageImport *parameters);
|
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,
|
Lardon3DProjectDbResult lardon3d_project_db_allocate_task_id(Lardon3DProjectDb *database,
|
||||||
uint64_t *task_id);
|
uint64_t *task_id);
|
||||||
Lardon3DProjectDbResult lardon3d_project_db_load_task(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_pairing.cpp',
|
||||||
'src/acquisition_ingest.cpp',
|
'src/acquisition_ingest.cpp',
|
||||||
'src/acquisition_campaign.cpp',
|
'src/acquisition_campaign.cpp',
|
||||||
|
'src/acquisition_campaign_task.cpp',
|
||||||
'src/feature_extractor_opencv.cpp',
|
'src/feature_extractor_opencv.cpp',
|
||||||
'src/feature_store.c',
|
'src/feature_store.c',
|
||||||
'src/feature_extractor_opencv.cpp',
|
'src/feature_extractor_opencv.cpp',
|
||||||
|
|
@ -195,6 +196,7 @@ executable(
|
||||||
'-DLARDON3D_TRACK_BUILDER_TASK_AVAILABLE',
|
'-DLARDON3D_TRACK_BUILDER_TASK_AVAILABLE',
|
||||||
'-DLARDON3D_SPARSE_SFM_TASK_AVAILABLE',
|
'-DLARDON3D_SPARSE_SFM_TASK_AVAILABLE',
|
||||||
'-DLARDON3D_INCREMENTAL_RECONSTRUCTION_TASK_AVAILABLE',
|
'-DLARDON3D_INCREMENTAL_RECONSTRUCTION_TASK_AVAILABLE',
|
||||||
|
'-DLARDON3D_ACQUISITION_CAMPAIGN_TASK_AVAILABLE',
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
ncursesw,
|
ncursesw,
|
||||||
|
|
@ -377,6 +379,24 @@ acquisition_campaign_test = executable(
|
||||||
|
|
||||||
test('acquisition-campaign', acquisition_campaign_test, timeout: 30)
|
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(
|
feature_store_test = executable(
|
||||||
'test-feature-store',
|
'test-feature-store',
|
||||||
sources: [
|
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 Lardon3DProjectDbVisualIndexUpdateTask *visual_parameters,
|
||||||
const Lardon3DProjectDbCandidatePairGenerateTask *candidate_parameters,
|
const Lardon3DProjectDbCandidatePairGenerateTask *candidate_parameters,
|
||||||
const Lardon3DProjectDbMatcherTask *matcher_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) {
|
if (!state || !state->project_loaded || !state->project_db) {
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_NO_PROJECT;
|
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(
|
? lardon3d_project_db_record_geometric_verifier_task(
|
||||||
state->project_db, &snapshot, task_kind, task_kind_version, &checkpoint,
|
state->project_db, &snapshot, task_kind, task_kind_version, &checkpoint,
|
||||||
geometric_parameters, now.tv_sec)
|
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,
|
: lardon3d_project_db_record_task(state->project_db, &snapshot, task_kind,
|
||||||
task_kind_version, &checkpoint, now.tv_sec);
|
task_kind_version, &checkpoint, now.tv_sec);
|
||||||
if (recorded == LARDON3D_PROJECT_DB_BUSY) {
|
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,
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_task(Lardon3DAppState *state,
|
||||||
const Lardon3DTask *task) {
|
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
|
Lardon3DProjectTaskCheckpointResult
|
||||||
|
|
@ -766,7 +771,15 @@ lardon3d_project_checkpoint_image_import_task(Lardon3DAppState *state, const Lar
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||||
}
|
}
|
||||||
return checkpoint_task_internal(
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_task(
|
||||||
|
|
@ -775,14 +788,16 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_feature_extract_
|
||||||
if (!parameters) {
|
if (!parameters) {
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_sift_extract_task(
|
||||||
Lardon3DAppState *state, const Lardon3DTask *task,
|
Lardon3DAppState *state, const Lardon3DTask *task,
|
||||||
const Lardon3DProjectDbSiftExtractTask *parameters) {
|
const Lardon3DProjectDbSiftExtractTask *parameters) {
|
||||||
if (!parameters) return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_visual_index_update_task(
|
||||||
|
|
@ -791,7 +806,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_visual_index_upd
|
||||||
if (!parameters) {
|
if (!parameters) {
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_candidate_pair_generate_task(
|
||||||
|
|
@ -800,7 +816,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_candidate_pair_g
|
||||||
if (!parameters) {
|
if (!parameters) {
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
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(
|
Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_matcher_task(
|
||||||
|
|
@ -809,7 +826,8 @@ Lardon3DProjectTaskCheckpointResult lardon3d_project_checkpoint_matcher_task(
|
||||||
if (!parameters) {
|
if (!parameters) {
|
||||||
return LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
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(
|
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 LARDON3D_PROJECT_TASK_CHECKPOINT_INVALID_TASK;
|
||||||
}
|
}
|
||||||
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL,
|
return checkpoint_task_internal(state, task, NULL, 0, NULL, NULL, NULL, NULL, NULL,
|
||||||
parameters);
|
parameters, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool coherent_recovery(const Lardon3DProjectDbTask *database_task,
|
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),"
|
"created_at INTEGER NOT NULL CHECK(created_at>=0),"
|
||||||
"CHECK(parent_asset_id!=child_asset_id));";
|
"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) {
|
static void copy_error(char destination[LARDON3D_PROJECT_DB_ERROR_CAPACITY], const char *text) {
|
||||||
if (destination) {
|
if (destination) {
|
||||||
(void)snprintf(destination, LARDON3D_PROJECT_DB_ERROR_CAPACITY, "%s", text ? text : "");
|
(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");
|
"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) {
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
result = execute(database, "COMMIT", "commit migration");
|
result = execute(database, "COMMIT", "commit migration");
|
||||||
}
|
}
|
||||||
|
|
@ -1228,7 +1257,9 @@ Lardon3DProjectDbResult lardon3d_project_db_open(const char *path, Lardon3DProje
|
||||||
"capture_images",
|
"capture_images",
|
||||||
"capture_assets",
|
"capture_assets",
|
||||||
"capture_selections",
|
"capture_selections",
|
||||||
"asset_derivations"};
|
"asset_derivations",
|
||||||
|
"acquisition_campaign_tasks",
|
||||||
|
"acquisition_campaign_captures"};
|
||||||
for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
|
for (size_t index = 0; index < sizeof(required) / sizeof(required[0]) &&
|
||||||
result == LARDON3D_PROJECT_DB_OK;
|
result == LARDON3D_PROJECT_DB_OK;
|
||||||
++index) {
|
++index) {
|
||||||
|
|
@ -1452,6 +1483,7 @@ record_task_internal(Lardon3DProjectDb *database, const Lardon3DTaskDurableSnaps
|
||||||
const Lardon3DProjectDbMatcherTask *matcher,
|
const Lardon3DProjectDbMatcherTask *matcher,
|
||||||
const Lardon3DProjectDbGeometricVerifierTask *geometric_verifier,
|
const Lardon3DProjectDbGeometricVerifierTask *geometric_verifier,
|
||||||
const Lardon3DProjectDbSparseSfmTask *sparse_sfm,
|
const Lardon3DProjectDbSparseSfmTask *sparse_sfm,
|
||||||
|
const Lardon3DProjectDbAcquisitionCampaignTask *campaign,
|
||||||
int64_t updated_at) {
|
int64_t updated_at) {
|
||||||
bool typed = task_kind != NULL;
|
bool typed = task_kind != NULL;
|
||||||
if (!database || !valid_durable_task(snapshot, updated_at) ||
|
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->track_set_id) ||
|
||||||
!valid_task_id(sparse_sfm->calibration_scope_id) || sparse_sfm->sfm_kind != 1 ||
|
!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))) ||
|
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))) {
|
(checkpoint && !valid_checkpoint(checkpoint))) {
|
||||||
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
|
|
@ -1582,6 +1619,26 @@ record_task_internal(Lardon3DProjectDb *database, const Lardon3DTaskDurableSnaps
|
||||||
}
|
}
|
||||||
#endif
|
#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) {
|
if (result == LARDON3D_PROJECT_DB_OK) {
|
||||||
result =
|
result =
|
||||||
prepare(database,
|
prepare(database,
|
||||||
|
|
@ -1916,7 +1973,7 @@ Lardon3DProjectDbResult lardon3d_project_db_record_task(
|
||||||
Lardon3DProjectDb *database, const Lardon3DTaskDurableSnapshot *snapshot, const char *task_kind,
|
Lardon3DProjectDb *database, const Lardon3DTaskDurableSnapshot *snapshot, const char *task_kind,
|
||||||
uint32_t task_kind_version, const Lardon3DProjectDbCheckpoint *checkpoint, int64_t updated_at) {
|
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,
|
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(
|
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,
|
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint,
|
||||||
source_path, scanset_id, NULL, NULL, NULL, NULL, NULL, NULL,
|
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(
|
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 LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint, NULL, 0,
|
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(
|
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) {
|
const Lardon3DProjectDbSiftExtractTask *parameters, int64_t updated_at) {
|
||||||
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
return record_task_internal(database, snapshot, task_kind, task_kind_version, checkpoint, NULL, 0,
|
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) {
|
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;
|
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_catalog_id(uint64_t value) { return value > 0 && value <= INT64_MAX; }
|
||||||
|
|
||||||
static bool valid_original_name(const char *name) {
|
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 LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
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(
|
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 LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
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(
|
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 LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
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(
|
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 LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
}
|
}
|
||||||
return record_task_internal(db, snapshot, kind, version, checkpoint, NULL, 0, NULL,
|
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(
|
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(
|
Lardon3DProjectDbResult result = record_task_internal(
|
||||||
db, snapshot, kind, version, checkpoint, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
|
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;
|
if (result != LARDON3D_PROJECT_DB_OK) return result;
|
||||||
(void)pthread_mutex_lock(&db->mutex);
|
(void)pthread_mutex_lock(&db->mutex);
|
||||||
result = execute(db, "BEGIN IMMEDIATE", "begin track builder task");
|
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) {
|
const Lardon3DProjectDbSparseSfmTask *parameters, int64_t updated_at) {
|
||||||
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
if (!parameters) return LARDON3D_PROJECT_DB_INVALID_ARGUMENT;
|
||||||
return record_task_internal(database, snapshot, kind, version, checkpoint, NULL, 0, NULL, NULL,
|
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) {
|
static bool read_u64_blob(sqlite3_stmt *statement, int column, uint64_t *value) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,7 @@
|
||||||
#include <lardon3d/candidate_pair_task.h>
|
#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/feature_task.h>
|
||||||
#include <lardon3d/geometric_verifier_task.h>
|
#include <lardon3d/geometric_verifier_task.h>
|
||||||
#include <lardon3d/import_task.h>
|
#include <lardon3d/import_task.h>
|
||||||
|
|
@ -18,6 +21,13 @@
|
||||||
|
|
||||||
const Lardon3DTaskKindRegistry *lardon3d_task_kind_registry_production(void) {
|
const Lardon3DTaskKindRegistry *lardon3d_task_kind_registry_production(void) {
|
||||||
static const Lardon3DTaskKindDescriptor descriptors[] = {
|
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 = LARDON3D_IMAGE_IMPORT_TASK_KIND,
|
||||||
.kind_version = LARDON3D_IMAGE_IMPORT_TASK_KIND_VERSION,
|
.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;
|
Lardon3DProjectDb *database = NULL;
|
||||||
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
CHECK(lardon3d_project_db_open(path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
LARDON3D_PROJECT_DB_OK);
|
||||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||||
Parents parents;
|
Parents parents;
|
||||||
CHECK(create_parents(database, &parents));
|
CHECK(create_parents(database, &parents));
|
||||||
|
|
||||||
|
|
@ -486,7 +486,7 @@ static bool test_migration(const char *v11_path, const char *failed_path) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(v11_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v11_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
LARDON3D_PROJECT_DB_OK);
|
||||||
CHECK(lardon3d_project_db_schema_version(database) == 19);
|
CHECK(lardon3d_project_db_schema_version(database) == 20);
|
||||||
Parents parents;
|
Parents parents;
|
||||||
CHECK(create_parents(database, &parents));
|
CHECK(create_parents(database, &parents));
|
||||||
unsigned char fingerprint[32] = {0x91};
|
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;
|
migrated_result.geometric_verification_result_id;
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
CHECK(query_integer(
|
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(
|
CHECK(
|
||||||
query_integer(v11_path,
|
query_integer(v11_path,
|
||||||
"SELECT count(*) FROM sqlite_master WHERE type='index' AND "
|
"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));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(failed_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,7 @@ static bool run_task_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
CHECK(remove_tree(root));
|
CHECK(remove_tree(root));
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ static bool run_test(void) {
|
||||||
Lardon3DProjectDb *database = NULL;
|
Lardon3DProjectDb *database = NULL;
|
||||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
LARDON3D_PROJECT_DB_OK);
|
||||||
CHECK(database && lardon3d_project_db_schema_version(database) == 19);
|
CHECK(database && lardon3d_project_db_schema_version(database) == 20);
|
||||||
|
|
||||||
Lardon3DProjectDbScanSet scanset;
|
Lardon3DProjectDbScanSet scanset;
|
||||||
CHECK(lardon3d_project_db_create_scanset(database, "Match-test", &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) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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 */
|
/* Verify persistence: load previously created results */
|
||||||
CHECK(lardon3d_project_db_load_match_result(database, first_id, &loaded) ==
|
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));
|
v9_path, "SELECT value FROM metadata WHERE key='schema_version'", 9));
|
||||||
CHECK(lardon3d_project_db_open(v9_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v9_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(
|
CHECK(
|
||||||
query_integer(v9_path,
|
query_integer(v9_path,
|
||||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||||
|
|
@ -576,7 +576,7 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(failed_v10_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v10_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -373,7 +373,7 @@ static bool run_test(void) {
|
||||||
"name='matcher_tasks'",
|
"name='matcher_tasks'",
|
||||||
0));
|
0));
|
||||||
CHECK(reopen_runtime(&fixture));
|
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(
|
CHECK(
|
||||||
query_integer(database_path,
|
query_integer(database_path,
|
||||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||||
|
|
|
||||||
|
|
@ -116,7 +116,7 @@ static bool create_future_database(const char *path) {
|
||||||
sqlite3_exec(
|
sqlite3_exec(
|
||||||
connection,
|
connection,
|
||||||
"CREATE TABLE metadata(key TEXT PRIMARY KEY,value INTEGER NOT NULL);"
|
"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;
|
NULL, NULL, NULL) == SQLITE_OK;
|
||||||
return sqlite3_close(connection) == SQLITE_OK && ok;
|
return sqlite3_close(connection) == SQLITE_OK && ok;
|
||||||
}
|
}
|
||||||
|
|
@ -940,7 +940,7 @@ static bool run_test(void) {
|
||||||
Lardon3DProjectDb *database = NULL;
|
Lardon3DProjectDb *database = NULL;
|
||||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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;
|
bool legacy_pending = true;
|
||||||
CHECK(lardon3d_project_db_legacy_catalog_pending(database, &legacy_pending) ==
|
CHECK(lardon3d_project_db_legacy_catalog_pending(database, &legacy_pending) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
|
@ -1499,7 +1499,7 @@ static bool run_test(void) {
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(database_path,
|
CHECK(query_integer(database_path,
|
||||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||||
19));
|
20));
|
||||||
CHECK(query_integer(database_path,
|
CHECK(query_integer(database_path,
|
||||||
"SELECT count(*) FROM tasks WHERE task_id=1", 1));
|
"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);"
|
"created_at) VALUES(1,1,1,1,1,zeroblob(32),1,2,1,0,0,1);"
|
||||||
"DROP TABLE incremental_reconstruction_tasks;"
|
"DROP TABLE incremental_reconstruction_tasks;"
|
||||||
"DROP TABLE incremental_reconstructions;"
|
"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 asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
||||||
CHECK(lardon3d_project_db_open(v17_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v17_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(v17_path,
|
CHECK(query_integer(v17_path,
|
||||||
|
|
@ -1550,6 +1551,7 @@ static bool run_test(void) {
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(execute_test_sql(
|
CHECK(execute_test_sql(
|
||||||
failed_v19_path,
|
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 asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||||
"UPDATE metadata SET value=18 WHERE key='schema_version';"));
|
"UPDATE metadata SET value=18 WHERE key='schema_version';"));
|
||||||
|
|
@ -1564,13 +1566,14 @@ static bool run_test(void) {
|
||||||
"name='captures'", 0));
|
"name='captures'", 0));
|
||||||
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v19_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(execute_test_sql(
|
CHECK(execute_test_sql(
|
||||||
failed_v18_path,
|
failed_v18_path,
|
||||||
"DROP TABLE incremental_reconstruction_tasks;"
|
"DROP TABLE incremental_reconstruction_tasks;"
|
||||||
"DROP TABLE incremental_reconstructions;"
|
"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 asset_derivations;DROP TABLE capture_selections;DROP TABLE capture_assets;"
|
||||||
"DROP TABLE capture_images;DROP TABLE captures;"
|
"DROP TABLE capture_images;DROP TABLE captures;"
|
||||||
"UPDATE metadata SET value=17 WHERE key='schema_version';"));
|
"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(create_v1_database(legacy_path));
|
||||||
CHECK(lardon3d_project_db_open(legacy_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(legacy_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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) ==
|
CHECK(lardon3d_project_db_get_project(database, &loaded_project) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
strcmp(loaded_project.stable_id, "legacy-project") == 0);
|
strcmp(loaded_project.stable_id, "legacy-project") == 0);
|
||||||
|
|
@ -1630,7 +1633,7 @@ static bool run_test(void) {
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(legacy_path,
|
CHECK(query_integer(legacy_path,
|
||||||
"SELECT value FROM metadata WHERE key='schema_version'",
|
"SELECT value FROM metadata WHERE key='schema_version'",
|
||||||
19));
|
20));
|
||||||
|
|
||||||
CHECK(create_v1_database(failed_migration_path));
|
CHECK(create_v1_database(failed_migration_path));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V2", "1", 1) == 0);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(create_v2_database(failed_v3_migration_path));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V3", "1", 1) == 0);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(create_v3_database(failed_v4_path));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V4", "1", 1) == 0);
|
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);
|
fprintf(stderr, "Migration v4 (%d): %s\n", (int)v4_result, error);
|
||||||
}
|
}
|
||||||
CHECK(v4_result == LARDON3D_PROJECT_DB_OK);
|
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) ==
|
CHECK(lardon3d_project_db_load_task(database, 9, &task) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
LARDON3D_PROJECT_DB_OK);
|
||||||
CHECK(lardon3d_project_db_load_artifact(database, "legacy-artifact",
|
CHECK(lardon3d_project_db_load_artifact(database, "legacy-artifact",
|
||||||
|
|
@ -1772,7 +1775,7 @@ static bool run_test(void) {
|
||||||
error);
|
error);
|
||||||
}
|
}
|
||||||
CHECK(retry_v7 == LARDON3D_PROJECT_DB_OK &&
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -1782,7 +1785,7 @@ static bool run_test(void) {
|
||||||
5));
|
5));
|
||||||
CHECK(lardon3d_project_db_open(direct_v5_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(direct_v5_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -1791,11 +1794,11 @@ static bool run_test(void) {
|
||||||
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 7));
|
v8_path, "SELECT value FROM metadata WHERE key='schema_version'", 7));
|
||||||
CHECK(lardon3d_project_db_open(v8_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v8_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(create_v7_database(failed_v8_path));
|
||||||
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V8", "1", 1) == 0);
|
CHECK(setenv("LARDON3D_TEST_PROJECT_DB_FAIL_MIGRATION_V8", "1", 1) == 0);
|
||||||
|
|
@ -1812,7 +1815,7 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(failed_v8_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v8_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -1831,11 +1834,11 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(v10_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v10_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(
|
CHECK(
|
||||||
query_integer(v10_path,
|
query_integer(v10_path,
|
||||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||||
|
|
@ -1862,7 +1865,7 @@ static bool run_test(void) {
|
||||||
1));
|
1));
|
||||||
CHECK(lardon3d_project_db_open(failed_v11_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v11_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -1876,11 +1879,11 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(v13_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(v13_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(query_integer(
|
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(
|
CHECK(
|
||||||
query_integer(v13_path,
|
query_integer(v13_path,
|
||||||
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
"SELECT count(*) FROM sqlite_master WHERE type='table' AND "
|
||||||
|
|
@ -1903,7 +1906,7 @@ static bool run_test(void) {
|
||||||
true_v14_path);
|
true_v14_path);
|
||||||
}
|
}
|
||||||
CHECK(true_v14_result == LARDON3D_PROJECT_DB_OK &&
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(
|
CHECK(
|
||||||
|
|
@ -2018,7 +2021,7 @@ static bool run_test(void) {
|
||||||
if (true_v15_result != LARDON3D_PROJECT_DB_OK)
|
if (true_v15_result != LARDON3D_PROJECT_DB_OK)
|
||||||
fprintf(stderr, "true v15 upgrade: %d %s\n", true_v15_result, error);
|
fprintf(stderr, "true v15 upgrade: %d %s\n", true_v15_result, error);
|
||||||
CHECK(true_v15_result == LARDON3D_PROJECT_DB_OK);
|
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;
|
Lardon3DProjectDbProject migrated_project;
|
||||||
CHECK(lardon3d_project_db_get_project(database, &migrated_project) ==
|
CHECK(lardon3d_project_db_get_project(database, &migrated_project) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
|
|
@ -2064,7 +2067,7 @@ static bool run_test(void) {
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(database_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
CHECK(schema_compare(database_path, true_v15_path, true));
|
CHECK(schema_compare(database_path, true_v15_path, true));
|
||||||
|
|
@ -2099,7 +2102,7 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(true_v15_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(true_v15_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK);
|
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);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -2118,7 +2121,7 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(failed_v14_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v14_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
@ -2137,7 +2140,7 @@ static bool run_test(void) {
|
||||||
0));
|
0));
|
||||||
CHECK(lardon3d_project_db_open(failed_v15_path, &database, error) ==
|
CHECK(lardon3d_project_db_open(failed_v15_path, &database, error) ==
|
||||||
LARDON3D_PROJECT_DB_OK &&
|
LARDON3D_PROJECT_DB_OK &&
|
||||||
lardon3d_project_db_schema_version(database) == 19);
|
lardon3d_project_db_schema_version(database) == 20);
|
||||||
lardon3d_project_db_close(database);
|
lardon3d_project_db_close(database);
|
||||||
database = NULL;
|
database = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ static bool run_test(void) {
|
||||||
Lardon3DProjectDb *db = NULL;
|
Lardon3DProjectDb *db = NULL;
|
||||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY];
|
||||||
CHECK(lardon3d_project_db_open(path, &db, error) == LARDON3D_PROJECT_DB_OK);
|
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;
|
Lardon3DProjectDbScanSet scanset;
|
||||||
CHECK(lardon3d_project_db_create_scanset(db, "Sparse model", &scanset) ==
|
CHECK(lardon3d_project_db_create_scanset(db, "Sparse model", &scanset) ==
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ int main() {
|
||||||
Lardon3DProjectDb *database = nullptr;
|
Lardon3DProjectDb *database = nullptr;
|
||||||
char error[LARDON3D_PROJECT_DB_ERROR_CAPACITY]{};
|
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_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;
|
sqlite3 *raw = nullptr;
|
||||||
CHECK(sqlite3_open(path.c_str(), &raw) == SQLITE_OK);
|
CHECK(sqlite3_open(path.c_str(), &raw) == SQLITE_OK);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue