Skip to content

Commit

Permalink
Fix inconsistency in snowflake schema with intermediate unused table
Browse files Browse the repository at this point in the history
Probleme explique en commentaire du nouvel attribut KWDatabase::nkdMutationClasses
  // Dictionnaire des classes de mutation, avec en cle la classe physique des objets a muter
  // et en valeur la classe suite a la mutation
  //
  // Dans la majorite des cas, la classe de mutation est la classe logique de meme nom,
  // qui garde les attributs charges en memoire de la classe logique, alors que la classe physique
  // a potentiellement plus d'attributs charges en memoire, en unused dans la classe logique, mais
  // necessaires dans la classe physique pour le calcul des attribut derives
  //
  // Dans des cas a effet de bord, la classe de mutation peut rester la classe physique si la classe
  // logique est en unused, mais est necessaire en tant qu'attribut de type relation non charge en
  // memoire, mais a garder pour la destruction des objets (cf. UnloadedOwnedRelationAttribute dans KWClass)
  // Exemple d'effet de bord:
  //   La classe Customer a des Services en Unused, ses services on des Usages, et la classe Customer
  //   a tous ses usages utilises via la regle TableSubUnion(Services, Usages)
  //   Dans ce cas, les Services physiques sont gardes dans leur classe physique pour gerer recursivement
  //   la destruction des Usages, mais ils ne sont pas mutes, car non utilises au niveau logique

Impacts principaux
- KWDatabase
  - BuildPhysicalClass: memorisation des classes de mutation dans le nouvel attribut nkdMutationClasses
  - MutatePhysicalObject: utilisation de nkdMutationClasses en parametre supplementaire
- KWDataTableSliceSet
  - PhysicalRead: adaptation miimaliste pour le parametrage supplementaire de la methode Mutate
- KWObject
  - Mutate: prend nkdMutationClasses pour gere les classe de mutation destination
  - on distingue la mutation de l'objet, qui n'est effectuee que si la classe de mutation est une nouvelle classe,
    de la mutation des attributs de type relation charges en memoire, qui est effectuee systematiquement
  - ajout de trace facilitant l'analyse des problème mémoire dans les methodes suivantes
    - KWObject (constructeur)
    - ComputeAllValues
    - DeleteAttributes
    - Mutate
    - PrettyWrite

Tous les tests de LearningTest passent, y compris en debug, sans fuite memoire
  • Loading branch information
marcboulle committed Dec 2, 2024
1 parent bd8d00a commit c77f2fb
Show file tree
Hide file tree
Showing 8 changed files with 584 additions and 391 deletions.
2 changes: 1 addition & 1 deletion src/Learning/KWDRRuleLibrary/KWDRBuildRelation.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class KWDRBuildTableView : public KWDRTableCreationRule

////////////////////////////////////////////////////////////////////////////
// Classe KWDRBuildTableAdvancedView
// Creation d'une vue sur une table, avec possibilite d'alimenter des attribut
// Creation d'une vue sur une table, avec possibilite d'alimenter des attributs
// de la table en sortie directement via des des operandes en sortie et
// des valeurs fournies par les operandes en entree corespondants
class KWDRBuildTableAdvancedView : public KWDRTableCreationRule
Expand Down
28 changes: 20 additions & 8 deletions src/Learning/KWData/KWDatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1213,6 +1213,7 @@ longint KWDatabase::GetUsedMemory() const
lUsedMemory = sizeof(KWDatabase);

// Memoire par attribut non elementaire
lUsedMemory += nkdMutationClasses.GetUsedMemory();
lUsedMemory += nkdUnusedNativeAttributesToKeep.GetUsedMemory();
lUsedMemory += oaAllObjects.GetUsedMemory();
lUsedMemory += sClassName.GetLength();
Expand Down Expand Up @@ -1595,12 +1596,22 @@ void KWDatabase::BuildPhysicalClass()
oaClassNeededAttributes.RemoveAll();
}

// Collecte de toutes les logiques necessaires
// Collecte de toutes les logiques necessaires, et memorisation des classe de mutations
assert(nkdMutationClasses.GetCount() == 0);
for (nClass = 0; nClass < oaAllNeededClasses.GetSize(); nClass++)
{
kwcCurrentPhysicalClass = cast(KWClass*, oaAllNeededClasses.GetAt(nClass));

// Recherche et memorisation de la classe logique correspondante
kwcInitialClass = kwcClass->GetDomain()->LookupClass(kwcCurrentPhysicalClass->GetName());
nkdNeededLogicalClasses.SetAt(kwcInitialClass, kwcInitialClass);

// Memorisation de la classe de mutation dans le cas ou une classe logique est explicitement utilisee
if (nkdNeededUsedClasses.Lookup(kwcCurrentPhysicalClass) != NULL)
nkdMutationClasses.SetAt(kwcCurrentPhysicalClass, kwcInitialClass);
// Sinon, on garde la classe physique, qui ne sera pas mutee
else
nkdMutationClasses.SetAt(kwcCurrentPhysicalClass, kwcCurrentPhysicalClass);
}

// Affichage des classes et attributs necessaires
Expand All @@ -1614,10 +1625,10 @@ void KWDatabase::BuildPhysicalClass()
{
kwcCurrentPhysicalClass = cast(KWClass*, oaAllNeededClasses.GetAt(nClass));
cout << "\t" << kwcCurrentPhysicalClass->GetName();
if (nkdNeededUsedClasses.Lookup(kwcCurrentPhysicalClass))
cout << "\tLogical";
else
cout << "\tPhysical";
cout << "\tDomain="
<< cast(KWClass*, nkdMutationClasses.Lookup(kwcCurrentPhysicalClass))
->GetDomain()
->GetName();
cout << endl;
}

Expand Down Expand Up @@ -2246,8 +2257,6 @@ void KWDatabase::ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDict
attribute->GetAnyDerivationRule());

// Memorisation de l'attribut natif ou cree sinon, s'il n'est pas utilise
//DDD On prend en fait en compte toutes les classes, sinon cela fait planter z_TableCreationRules\BugDeleteSubTableOfView
//DDD le parametre nkdNeededClasses est donc a ignorer et inutile!!!
if (not attribute->IsInBlock() and not attribute->GetReference() and
not attribute->GetUsed() and
nkdNeededClasses->Lookup(attribute->GetClass()) != NULL)
Expand Down Expand Up @@ -2296,6 +2305,9 @@ void KWDatabase::DeletePhysicalClass()
kwcCurrentClass->GetDatabaseTemporayDataItemsToComputeAndClean()->SetSize(0);
}

// Nettoyage du dictionnaire des classes de mutation
nkdMutationClasses.RemoveAll();

// Nettoyage du dictionnaire des attribut natif non utilises a detruire
nkdUnusedNativeAttributesToKeep.RemoveAll();
}
Expand Down Expand Up @@ -2340,7 +2352,7 @@ void KWDatabase::MutatePhysicalObject(KWObject* kwoPhysicalObject) const

// Mutation si necessaire
if (kwcPhysicalClass != kwcClass)
kwoPhysicalObject->Mutate(kwcClass, &nkdUnusedNativeAttributesToKeep);
kwoPhysicalObject->Mutate(kwcClass, &nkdMutationClasses, &nkdUnusedNativeAttributesToKeep);

// Trace apres mutation
if (bTrace)
Expand Down
20 changes: 19 additions & 1 deletion src/Learning/KWData/KWDatabase.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ class KWDatabase : public Object
// Calcul du dictionnaire des attributs natifs inutilises a garder, en precisant les classes qui sont necessaires
void ComputeUnusedNativeAttributesToKeep(const NumericKeyDictionary* nkdNeededClasses,
NumericKeyDictionary* nkdAttributes);
void ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDictionary* nkdClassesToKeep,
void ComputeUnusedNativeAttributesToKeepForRule(const NumericKeyDictionary* nkdNeededClasses,
NumericKeyDictionary* nkdAttributes,
NumericKeyDictionary* nkdAnalysedRules, KWDerivationRule* rule);

Expand Down Expand Up @@ -558,6 +558,24 @@ class KWDatabase : public Object
// Meme remarque que pour kwcClass, mais uniquement en lecture.
KWClass* kwcPhysicalClass;

// Dictionnaire des classes de mutation, avec en cle la classe physique des objets a muter
// et en valeur la classe suite a la mutation
//
// Dans la majorite des cas, la classe de mutation est la classe logique de meme nom,
// qui garde les attributs charges en memoire de la classe logique, alors que la classe physique
// a potentiellement plus d'attributs charges en memoire, en unused dans la classe logique, mais
// necessaires dans la classe physique pour le calcul des attribut derives
//
// Dans des cas a effet de bord, la classe de mutation peut rester la classe physique si la classe
// logique est en unused, mais est necessaire en tant qu'attribut de type relation non charge en
// memoire, mais a garder pour la destruction des objets (cf. UnloadedOwnedRelationAttribute dans KWClass)
// Exemple d'effet de bord:
// La classe Customer a des Services en Unused, ses services on des Usages, et la classe Customer
// a tous ses usages utilises via la regle TableSubUnion(Services, Usages)
// Dans ce cas, les Services physiques sont gardes dans leur classe physique pour gerer recursivement
// la destruction des Usages, mais ils ne sont pas mutes, car non utilises au niveau logique
NumericKeyDictionary nkdMutationClasses;

// Dictionnaire des attributs natifs Object ou ObjectArray a garder lors des mutations d'objet
// Utile dans le cas multi-table, que ce soit dans le cas d'un schema multi-table "logique"
// avec des fichiers mappes pour chaque table secondaire ou un schema multi-table "conceptuel"
Expand Down
Loading

0 comments on commit c77f2fb

Please sign in to comment.