Skip to content

Commit

Permalink
Perfdataloader: Fix table load order based on foreign key dependencie…
Browse files Browse the repository at this point in the history
…s. (#140)

* Perfdataloader: Fix table load order based on foreign key dependencies.
  • Loading branch information
shaharuk-yb authored Aug 13, 2024
1 parent 0fffc14 commit a6d2723
Showing 1 changed file with 77 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class DataGeneratorLoader extends Loader<DataGenerator> {
private final Map<String, FkPropertyMapping> fkProperties;

private final Map<String, PropertyMapping> pkProperties;
private int minLevel = Integer.MAX_VALUE;

public DataGeneratorLoader(DataGenerator benchmark, Map<String, PropertyMapping> properties,
Map<String, PropertyMapping> pkProperties, Map<String, FkPropertyMapping> fkProperties) {
Expand Down Expand Up @@ -280,6 +281,17 @@ public static List<String> getParentTableHierarchy(String tableName, Connection
return tableHierarchy;
}

public static void buildDependencyDAGForTable(Map<String, List<Dependency>> graph, List<ForeignKey> foreignKeyList, Connection conn) {
// Build the adjacency list
for (ForeignKey fk : foreignKeyList) {
graph.computeIfAbsent(fk.getTableName(), k -> new ArrayList<>()).add(new Dependency(fk.getForeignTableName(), -1));
List<ForeignKey> fkOfFks = getForeignKeys(fk.getForeignTableName(), conn);
if (!fkOfFks.isEmpty()) {
buildDependencyDAGForTable(graph, fkOfFks, conn);
}
}
}

private static void findParentTables(String tableName, Connection conn, List<String> tableHierarchy) {
List<ForeignKey> foreignKeys = getForeignKeys(tableName, conn);

Expand Down Expand Up @@ -498,16 +510,23 @@ public void getDistinctValuesFromParentTable(Connection conn, List<ForeignKey> f
distinctValues.add(rs.getObject(1));
}
if (distinctValues.isEmpty()) {
List<String> hierarchy = getParentTableHierarchy(foreignKey.getForeignTableName(), conn);
Map<Integer, String> levelAndTables = new LinkedHashMap<>();
Map<String, List<Dependency>> graph = new HashMap<>();
Map<Integer, List<String>> depth = new TreeMap<>();
Set<String> visited = new HashSet<>();

buildDependencyDAGForTable(graph, foreignKeyList, conn);

StringBuilder loadOrder = new StringBuilder(String.format("There are no entries in the parent " +
"table `%s` for column `%s` to be used as foreign key. Consider loading tables in " +
"following order: ", foreignKey.getForeignTableName(),
"following order/Levels(tables from `Level 0` first, then `Level 1` and so on: ", foreignKey.getForeignTableName(),
foreignKey.getForeignColumnName()));
for (String table : hierarchy) {
loadOrder.append(table).append(" --> ");

for (String table : graph.keySet()) {
if (!visited.contains(table)) {
getOrderOfImport(table, loadOrder, graph, depth, visited);
}
}
loadOrder.append(foreignKey.getTableName());
throw new RuntimeException(loadOrder.toString());
}
foreignKey.setDistinctValues(distinctValues);
Expand Down Expand Up @@ -598,4 +617,57 @@ protected Set<Property> createPropertySet(Class<?> type, BeanAccess bAccess) {
return properties;
}
}

// Helper class to store table name and level change
public static class Dependency {
String table;
int levelChange;

Dependency(String table, int levelChange) {
this.table = table;
this.levelChange = levelChange;
}
}

// Function to print nodes by levels
public void getOrderOfImport(String startTable, StringBuilder loadOrder,
Map<String, List<Dependency>> graph , Map<Integer, List<String>> depth,
Set<String> visited) {
dfs(startTable, 0, graph, depth, visited);

// Adjust levels to start from 0
Map<Integer, List<String>> adjustedDepth = new TreeMap<>();
for (Map.Entry<Integer, List<String>> entry : depth.entrySet()) {
int adjustedLevel = entry.getKey() - minLevel;
adjustedDepth.computeIfAbsent(adjustedLevel, k -> new ArrayList<>()).addAll(entry.getValue());
}

// Output the final levels of nodes
for (Map.Entry<Integer, List<String>> entry : adjustedDepth.entrySet()) {
int level = entry.getKey();
List<String> tablesAtLevel = entry.getValue();
loadOrder.append("\n").append("Level ").append(level).append(": ").append(String.join(", ", tablesAtLevel));
}

}

// DFS function to populate the levels map
public void dfs(String table, int level, Map<String, List<Dependency>> graph , Map<Integer, List<String>> depth,
Set<String> visited) {
visited.add(table);
depth.computeIfAbsent(level, k -> new ArrayList<>()).add(table);

// Update the minimum level encountered
if (level < minLevel) {
minLevel = level;
}

if (graph.containsKey(table)) {
for (Dependency dep : graph.get(table)) {
if (!visited.contains(dep.table)) {
dfs(dep.table, level + dep.levelChange, graph, depth, visited);
}
}
}
}
}

0 comments on commit a6d2723

Please sign in to comment.