wire-in hookdispatcher thru connection/etc

This commit is contained in:
Zoltan Haindrich 2024-07-30 12:29:36 +00:00
parent 78b75d3e8e
commit 9ac26e3a89
9 changed files with 58 additions and 18 deletions

View File

@ -22,6 +22,7 @@ package org.apache.druid.quidem;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.apache.druid.guice.LazySingleton; import org.apache.druid.guice.LazySingleton;
import org.apache.druid.java.util.common.StringUtils; import org.apache.druid.java.util.common.StringUtils;
import org.apache.druid.sql.hook.DruidHookDispatcher;
import javax.inject.Named; import javax.inject.Named;
import javax.ws.rs.GET; import javax.ws.rs.GET;
@ -40,11 +41,13 @@ public class QuidemCaptureResource
.getPathFromProjectRoot("quidem-it/src/test/quidem/org.apache.druid.quidem.QTest"); .getPathFromProjectRoot("quidem-it/src/test/quidem/org.apache.druid.quidem.QTest");
private URI quidemURI; private URI quidemURI;
private QuidemRecorder recorder = null; private QuidemRecorder recorder = null;
private DruidHookDispatcher hookDispatcher;
@Inject @Inject
public QuidemCaptureResource(@Named("quidem") URI quidemURI) public QuidemCaptureResource(@Named("quidem") URI quidemURI, DruidHookDispatcher hookDispatcher)
{ {
this.quidemURI = quidemURI; this.quidemURI = quidemURI;
this.hookDispatcher = hookDispatcher;
} }
@GET @GET
@ -55,6 +58,7 @@ public class QuidemCaptureResource
stopIfRunning(); stopIfRunning();
recorder = new QuidemRecorder( recorder = new QuidemRecorder(
quidemURI, quidemURI,
hookDispatcher,
genRecordFilePath() genRecordFilePath()
); );
return recorder.toString(); return recorder.toString();

View File

@ -20,6 +20,7 @@
package org.apache.druid.quidem; package org.apache.druid.quidem;
import org.apache.druid.sql.hook.DruidHook; import org.apache.druid.sql.hook.DruidHook;
import org.apache.druid.sql.hook.DruidHookDispatcher;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
@ -34,9 +35,11 @@ public class QuidemRecorder implements AutoCloseable, DruidHook<String>
{ {
private PrintStream printStream; private PrintStream printStream;
private File file; private File file;
private DruidHookDispatcher hookDispatcher;
public QuidemRecorder(URI quidemURI, File file) public QuidemRecorder(URI quidemURI, DruidHookDispatcher hookDispatcher, File file)
{ {
this.hookDispatcher = hookDispatcher;
this.file = file; this.file = file;
try { try {
this.printStream = new PrintStream(new FileOutputStream(file), true, StandardCharsets.UTF_8.name()); this.printStream = new PrintStream(new FileOutputStream(file), true, StandardCharsets.UTF_8.name());
@ -47,7 +50,7 @@ public class QuidemRecorder implements AutoCloseable, DruidHook<String>
printStream.println("#started " + new Date()); printStream.println("#started " + new Date());
printStream.println("!use " + quidemURI); printStream.println("!use " + quidemURI);
printStream.println("!set outputformat mysql"); printStream.println("!set outputformat mysql");
DruidHook.register(DruidHook.SQL, this); hookDispatcher.register(DruidHook.SQL, this);
} }
@Override @Override
@ -57,7 +60,7 @@ public class QuidemRecorder implements AutoCloseable, DruidHook<String>
printStream.close(); printStream.close();
printStream = null; printStream = null;
} }
DruidHook.unregister(DruidHook.SQL, this); hookDispatcher.unregister(DruidHook.SQL, this);
} }
@Override @Override

View File

@ -395,7 +395,8 @@ public class CalciteRulesManager
public RelNode run(RelOptPlanner planner, RelNode rel, RelTraitSet requiredOutputTraits, public RelNode run(RelOptPlanner planner, RelNode rel, RelTraitSet requiredOutputTraits,
List<RelOptMaterialization> materializations, List<RelOptLattice> lattices) List<RelOptMaterialization> materializations, List<RelOptLattice> lattices)
{ {
DruidHook.dispatch(DruidHook.LOGICAL_PLAN, rel); PlannerContext pctx = planner.getContext().unwrapOrThrow(PlannerContext.class);
pctx.dispatchHook(DruidHook.LOGICAL_PLAN, rel);
return rel; return rel;
} }
} }

View File

@ -155,7 +155,7 @@ public abstract class QueryHandler extends SqlStatementHandler.BaseStatementHand
isPrepared = true; isPrepared = true;
SqlNode validatedQueryNode = validatedQueryNode(); SqlNode validatedQueryNode = validatedQueryNode();
rootQueryRel = handlerContext.planner().rel(validatedQueryNode); rootQueryRel = handlerContext.planner().rel(validatedQueryNode);
DruidHook.dispatch(DruidHook.CONVERTED_PLAN, rootQueryRel.rel); handlerContext.plannerContext().dispatchHook(DruidHook.CONVERTED_PLAN, rootQueryRel.rel);
handlerContext.hook().captureQueryRel(rootQueryRel); handlerContext.hook().captureQueryRel(rootQueryRel);
final RelDataTypeFactory typeFactory = rootQueryRel.rel.getCluster().getTypeFactory(); final RelDataTypeFactory typeFactory = rootQueryRel.rel.getCluster().getTypeFactory();
final SqlValidator validator = handlerContext.planner().getValidator(); final SqlValidator validator = handlerContext.planner().getValidator();
@ -592,7 +592,7 @@ public abstract class QueryHandler extends SqlStatementHandler.BaseStatementHand
handlerContext.hook().captureDruidRel(druidRel); handlerContext.hook().captureDruidRel(druidRel);
DruidHook.dispatch(DruidHook.DRUID_PLAN, druidRel); plannerContext.dispatchHook(DruidHook.DRUID_PLAN, druidRel);
if (explain != null) { if (explain != null) {
return planExplanation(possiblyLimitedRoot, druidRel, true); return planExplanation(possiblyLimitedRoot, druidRel, true);

View File

@ -78,31 +78,31 @@ public interface DruidHook<T>
@SuppressFBWarnings({"MS_OOI_PKGPROTECT"}) @SuppressFBWarnings({"MS_OOI_PKGPROTECT"})
Map<HookKey<?>, List<DruidHook<?>>> GLOBAL = new HashMap<>(); Map<HookKey<?>, List<DruidHook<?>>> GLOBAL = new HashMap<>();
static void register(HookKey<?> label, DruidHook<?> hook) static void register1(HookKey<?> label, DruidHook<?> hook)
{ {
GLOBAL.computeIfAbsent(label, k -> new ArrayList<>()).add(hook); GLOBAL.computeIfAbsent(label, k -> new ArrayList<>()).add(hook);
} }
static void unregister(HookKey<?> key, DruidHook<?> hook) static void unregister1(HookKey<?> key, DruidHook<?> hook)
{ {
GLOBAL.get(key).remove(hook); GLOBAL.get(key).remove(hook);
} }
static <T> Closeable withHook(HookKey<T> key, DruidHook<T> hook) static <T> Closeable withHook1(HookKey<T> key, DruidHook<T> hook)
{ {
register(key, hook); register1(key, hook);
return new Closeable() return new Closeable()
{ {
@Override @Override
public void close() public void close()
{ {
unregister(key, hook); unregister1(key, hook);
} }
}; };
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
static <T> void dispatch(HookKey<T> key, T object) static <T> void dispatch12(HookKey<T> key, T object)
{ {
List<DruidHook<?>> hooks = GLOBAL.get(key); List<DruidHook<?>> hooks = GLOBAL.get(key);
if (hooks != null) { if (hooks != null) {

View File

@ -20,6 +20,7 @@
package org.apache.druid.sql.hook; package org.apache.druid.sql.hook;
import com.google.inject.Inject; import com.google.inject.Inject;
import org.apache.druid.guice.LazySingleton;
import org.apache.druid.sql.hook.DruidHook.HookKey; import org.apache.druid.sql.hook.DruidHook.HookKey;
import java.io.Closeable; import java.io.Closeable;
@ -28,6 +29,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@LazySingleton
public class DruidHookDispatcher public class DruidHookDispatcher
{ {
@Inject @Inject

View File

@ -70,6 +70,7 @@ import org.apache.druid.sql.calcite.util.SqlTestFramework.Builder;
import org.apache.druid.sql.calcite.util.SqlTestFramework.PlannerComponentSupplier; import org.apache.druid.sql.calcite.util.SqlTestFramework.PlannerComponentSupplier;
import org.apache.druid.sql.calcite.util.SqlTestFramework.QueryComponentSupplier; import org.apache.druid.sql.calcite.util.SqlTestFramework.QueryComponentSupplier;
import org.apache.druid.sql.guice.SqlModule; import org.apache.druid.sql.guice.SqlModule;
import org.apache.druid.sql.hook.DruidHookDispatcher;
import org.apache.http.client.utils.URIBuilder; import org.apache.http.client.utils.URIBuilder;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
@ -138,9 +139,9 @@ public class DruidAvaticaTestDriver implements Driver
@Provides @Provides
@LazySingleton @LazySingleton
public DruidConnectionExtras getConnectionExtras(ObjectMapper objectMapper) public DruidConnectionExtras getConnectionExtras(ObjectMapper objectMapper, DruidHookDispatcher druidHookDispatcher)
{ {
return new DruidConnectionExtras.DruidConnectionExtrasImpl(objectMapper); return new DruidConnectionExtras.DruidConnectionExtrasImpl(objectMapper, druidHookDispatcher);
} }
@Provides @Provides

View File

@ -20,18 +20,25 @@
package org.apache.druid.quidem; package org.apache.druid.quidem;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.druid.sql.hook.DruidHookDispatcher;
import java.sql.Connection;
public interface DruidConnectionExtras public interface DruidConnectionExtras
{ {
ObjectMapper getObjectMapper(); ObjectMapper getObjectMapper();
DruidHookDispatcher getDruidHookDispatcher();
class DruidConnectionExtrasImpl implements DruidConnectionExtras class DruidConnectionExtrasImpl implements DruidConnectionExtras
{ {
private final ObjectMapper objectMapper; private final ObjectMapper objectMapper;
private final DruidHookDispatcher druidHookDispatcher;
public DruidConnectionExtrasImpl(ObjectMapper objectMapper) public DruidConnectionExtrasImpl(ObjectMapper objectMapper, DruidHookDispatcher druidHookDispatcher)
{ {
this.objectMapper = objectMapper; this.objectMapper = objectMapper;
this.druidHookDispatcher = druidHookDispatcher;
} }
@Override @Override
@ -39,5 +46,20 @@ public interface DruidConnectionExtras
{ {
return objectMapper; return objectMapper;
} }
@Override
public DruidHookDispatcher getDruidHookDispatcher()
{
return druidHookDispatcher;
}
} }
static DruidConnectionExtras unwrapOrThrow(Connection connection)
{
if(connection instanceof DruidConnectionExtras ) {
return (DruidConnectionExtras) connection;
}
throw new UnsupportedOperationException("Expected DruidConnectionExtras to be implemented by connection!");
}
} }

View File

@ -37,10 +37,12 @@ import org.apache.druid.sql.calcite.rel.DruidRel;
import org.apache.druid.sql.calcite.util.QueryLogHook; import org.apache.druid.sql.calcite.util.QueryLogHook;
import org.apache.druid.sql.hook.DruidHook; import org.apache.druid.sql.hook.DruidHook;
import org.apache.druid.sql.hook.DruidHook.HookKey; import org.apache.druid.sql.hook.DruidHook.HookKey;
import org.apache.druid.sql.hook.DruidHookDispatcher;
import java.io.Closeable; import java.io.Closeable;
import java.io.IOException; import java.io.IOException;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -167,10 +169,11 @@ public class DruidQuidemCommandHandler implements CommandHandler
} }
@Override @Override
protected final void executeExplain(Context x) throws IOException protected final void executeExplain(Context x) throws IOException, SQLException
{ {
DruidHookDispatcher dhp = unwrapDruidHookDispatcher(x);
List<RelNode> logged = new ArrayList<>(); List<RelNode> logged = new ArrayList<>();
try (Closeable unhook = DruidHook.withHook(hook, (key, relNode) -> { try (Closeable unhook = dhp.withHook(hook, (key, relNode) -> {
logged.add(relNode); logged.add(relNode);
})) { })) {
executeQuery(x); executeQuery(x);
@ -184,6 +187,10 @@ public class DruidQuidemCommandHandler implements CommandHandler
x.echo(ImmutableList.of(str)); x.echo(ImmutableList.of(str));
} }
} }
protected final DruidHookDispatcher unwrapDruidHookDispatcher(Context x) {
return DruidConnectionExtras.unwrapOrThrow(x.connection()).getDruidHookDispatcher();
}
} }
static class LogicalPlanCommand extends AbstractRelPlanCommand static class LogicalPlanCommand extends AbstractRelPlanCommand