-
Notifications
You must be signed in to change notification settings - Fork 214
LIHADOOP-86205: Add view dependency tracking to capture full view lineage chain #577
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 1 commit
55e1798
588161f
b502f1c
991908e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,4 +18,5 @@ ligradle | |
| .DS_Store | ||
| *.patch | ||
| */metastore_db | ||
| .pyc | ||
| .pyc | ||
| __pycache__/ | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| /** | ||
| * Copyright 2017-2026 LinkedIn Corporation. All rights reserved. | ||
| * Licensed under the BSD-2 Clause license. | ||
| * See LICENSE in the project root for license information. | ||
| */ | ||
| package com.linkedin.coral.common; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Objects; | ||
|
|
||
|
|
||
| /** | ||
| * Represents a single node in the view dependency chain. | ||
| * For a view "db.v1" that depends on "db.v2" and "db.t1", | ||
| * this would be: ViewDependency("db.v1", ["db.v2", "db.t1"]) | ||
| */ | ||
| public class ViewDependency { | ||
| private final String viewName; | ||
| private final List<String> dependencies; | ||
|
|
||
| public ViewDependency(String viewName, List<String> dependencies) { | ||
| this.viewName = viewName; | ||
| this.dependencies = dependencies; | ||
| } | ||
|
|
||
| public String getViewName() { | ||
| return viewName; | ||
| } | ||
|
|
||
| public List<String> getDependencies() { | ||
| return dependencies; | ||
| } | ||
|
|
||
| @Override | ||
| public boolean equals(Object o) { | ||
| if (this == o) { | ||
| return true; | ||
| } | ||
| if (o == null || getClass() != o.getClass()) { | ||
| return false; | ||
| } | ||
| ViewDependency that = (ViewDependency) o; | ||
| return Objects.equals(viewName, that.viewName) && Objects.equals(dependencies, that.dependencies); | ||
| } | ||
|
|
||
| @Override | ||
| public int hashCode() { | ||
| return Objects.hash(viewName, dependencies); | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return "ViewDependency{view=" + viewName + ", deps=" + dependencies + "}"; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /** | ||
| * Copyright 2017-2026 LinkedIn Corporation. All rights reserved. | ||
| * Licensed under the BSD-2 Clause license. | ||
| * See LICENSE in the project root for license information. | ||
| */ | ||
| package com.linkedin.coral.common; | ||
|
|
||
| import java.util.ArrayDeque; | ||
| import java.util.ArrayList; | ||
| import java.util.Deque; | ||
| import java.util.LinkedHashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
|
|
||
|
|
||
| /** | ||
| * Thread-local tracker that records view to [immediate dependencies] mappings | ||
| * during Calcite view expansion. | ||
| */ | ||
| public class ViewDependencyTracker { | ||
| private static final ThreadLocal<ViewDependencyTracker> INSTANCE = | ||
| ThreadLocal.withInitial(ViewDependencyTracker::new); | ||
|
|
||
| private final Map<String, List<String>> viewDeps = new LinkedHashMap<>(); | ||
|
|
||
| private final Deque<String> expansionStack = new ArrayDeque<>(); | ||
|
|
||
| public static ViewDependencyTracker get() { | ||
| return INSTANCE.get(); | ||
| } | ||
|
|
||
| public static void reset() { | ||
| INSTANCE.remove(); | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After each resolution, the state needs to be cleared - not just in tests, but also for 'regular' use
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, this method will be invoked from the caller who invokes the rel converter of Coral |
||
|
|
||
| /** | ||
| * Called at the START of expanding a view. | ||
| */ | ||
| public void enterView(String dbName, String tableName) { | ||
| String qualifiedName = dbName + "." + tableName; | ||
| // Record this view as a dependency of the current parent | ||
| if (!expansionStack.isEmpty()) { | ||
| String parent = expansionStack.peek(); | ||
| viewDeps.computeIfAbsent(parent, k -> new ArrayList<>()).add(qualifiedName); | ||
| } | ||
| expansionStack.push(qualifiedName); | ||
| } | ||
|
|
||
| /** | ||
| * Called when a base table (non-view) is encountered during view expansion. | ||
| */ | ||
| public void recordBaseDependency(String dbName, String tableName) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| String qualifiedName = dbName + "." + tableName; | ||
| if (!expansionStack.isEmpty()) { | ||
| String parent = expansionStack.peek(); | ||
| viewDeps.computeIfAbsent(parent, k -> new ArrayList<>()).add(qualifiedName); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Called at the END of expanding a view. | ||
| */ | ||
| public void exitView() { | ||
| if (!expansionStack.isEmpty()) { | ||
| expansionStack.pop(); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Returns the collected view dependency chain. | ||
| * Each entry represents a view and its immediate dependencies (both views and base tables). | ||
| */ | ||
| public List<ViewDependency> getViewDependencies() { | ||
| List<ViewDependency> result = new ArrayList<>(); | ||
| for (Map.Entry<String, List<String>> entry : viewDeps.entrySet()) { | ||
| result.add(new ViewDependency(entry.getKey(), entry.getValue())); | ||
| } | ||
| return result; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return and validate it is the same view ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a check for validating the return of
exitView