[CDAP-21172] Add Creation/Deletion logic for Metadata Tables #15971
Conversation
51d0b07 to
ef67afc
Compare
sidhdirenge
left a comment
There was a problem hiding this comment.
We are missing one important thing here - table updates. Updates would need some extra checks like schema backward compatibility, no new insertion of Primary keys etc.
This is out of scope for this PR but we can add a TODO related to handling schema updates.
| static final String PROJECT = "project"; | ||
| static final String INSTANCE = "instance"; | ||
| static final String DATABASE = "database"; |
There was a problem hiding this comment.
can we make these fields private?
There was a problem hiding this comment.
We will be using these fields for unit tests so we use them or we can add getter methods for them.
There was a problem hiding this comment.
We can mock it. It should not be difficult
|
|
||
| private static final Logger LOG = LoggerFactory.getLogger(SpannerMetadataStorage.class); | ||
|
|
||
| private static final String METADATA_TABLE = "metadata"; // Table name |
There was a problem hiding this comment.
no need of line comments to explain the purpose of variables.
You can instead divide these variables into sections and add comments like:
// Metadata storage tables
private static final String METADATA_TABLE = "metadata";
private static final String METADATA_PROPS_TABLE = "metadata_props";
// `metadata` table fields
.
.
.
// `metadata_props` table fields
.
.
| private static final String TYPE_FIELD = "entity_type"; // Type of the entity (e.g., dataset, application) | ||
| private static final String NAME_FIELD = "name"; // Name of the entity | ||
| private static final String CREATED_FIELD = "creation_time"; // creation-time | ||
| private static final String User_FIELD = "user"; // USER-scoped properties/tags |
| private String instanceId = "instance"; | ||
| private String databaseId = "database"; | ||
| private String projectId = "project"; |
There was a problem hiding this comment.
Why are we initializing these values?
There was a problem hiding this comment.
+1 this should be configured by cdapmaster
| LOG.error("Error executing DDL statements: {}", e.getMessage(), e); | ||
| throw new IOException(e); |
There was a problem hiding this comment.
no need of extra logger here - IOException will print the entire stack trace in the logs.
| @Override | ||
| public void dropIndex() throws IOException { | ||
| throw new IOException("NOT IMPLEMENTED"); | ||
| synchronized (this) { |
There was a problem hiding this comment.
No need of synchronization here. You can just silently ignore exception if table does not exist.
| statements.add(String.format("DROP TABLE IF EXISTS %s", METADATA_PROPS_TABLE)); | ||
| try { | ||
| executeCreateDDLStatements(statements); | ||
| LOG.info("Table dropped successfully."); |
There was a problem hiding this comment.
Logger not very informational - which table was dropped?
| executeCreateDDLStatements(statements); | ||
| LOG.info("Table dropped successfully."); | ||
| } catch (IOException e) { | ||
| LOG.error("Error dropping index: {}", e.getMessage(), e); |
There was a problem hiding this comment.
No need of extra logger here.
| } | ||
|
|
||
| /** | ||
| * <p>Key features of the schema: |
There was a problem hiding this comment.
Feel free to add some examples in the javadocs like we have done in messaging - https://github.com/cdapio/cdap/blob/develop/cdap-messaging-ext-spanner/src/main/java/io/cdap/cdap/messaging/spanner/SpannerMessagingService.java#L304
Whenever someone will see this code for the first time, it will be easy for them to understand why 2 tables were needed here.
| "Value_Tokens TOKENLIST AS " + | ||
| "(TOKENIZE_SUBSTRING(Props_Value, ngram_size_min=>1, ngram_size_max=>3)) HIDDEN," + | ||
| ")PRIMARY KEY (metadata_id, %s, %s) ," + // primary key | ||
| "INTERLEAVE IN PARENT metadata ON DELETE CASCADE", |
There was a problem hiding this comment.
metadata can be replaced with table name defined at the start.
| LOG.info("Generating create table DDL statement."); | ||
| return String.format( | ||
| "CREATE TABLE IF NOT EXISTS %s (" + | ||
| "Metadata_ID STRING(MAX) NOT NULL," + |
There was a problem hiding this comment.
metadata_id can also be defined as another constant with field name.
| "%s STRING(MAX)," + // system | ||
| "metadata_column JSON," + // metadata | ||
| "VERSION INT64 NOT NULL," + | ||
| "User_Tokens TOKENLIST AS " + |
There was a problem hiding this comment.
column names should always be -> user_tokens, system_tokens, text_tokens
| } | ||
| return cConf.get(PROJECT); | ||
| } | ||
| } No newline at end of file |
| @@ -16,6 +16,15 @@ | |||
|
|
|||
| package io.cdap.cdap.metadata.spanner; | |||
|
|
|||
There was a problem hiding this comment.
Can we add test file for this class?
cc @sidhdirenge
| String instance = cConf.get(DATABASE); | ||
| if (instance == null) { | ||
| throw new IllegalArgumentException("Missing configuration " + DATABASE); | ||
| } |
There was a problem hiding this comment.
- why the variable name is instance?
- When we already have the data in instance variable why are we fetching that again?
- Cant we use Objects.requireNonNull() function that will throw the null pointed exception simply?
| } | ||
|
|
||
| static String getProjectID(Map<String, String> cConf) { | ||
| String instance = cConf.get(PROJECT); |
There was a problem hiding this comment.
- why the variable name is instance?
- When we already have the data in instance variable why are we fetching that again?
- Cant we use Objects.requireNonNull() function that will throw the null pointed exception simply?
| if (created) { | ||
| return; | ||
| } | ||
| synchronized (this) { |
There was a problem hiding this comment.
Avoid synchronizing on this. It locks the entire object and can block threads unnecessarily. Instead, if needed synchronize only on the specific objects that require protection.
94e5d3b to
f0b7cc5
Compare
| private static final String METADATA_ID_FIELD = "metadata_id"; // metadata_id of the metadata | ||
| private static final String METADATA_COLUMN_FIELD = "metadata_column"; // contains the metadata | ||
| private static final String NAMESPACE_FIELD = "namespace"; // namespace of the metadata | ||
| private static final String TYPE_FIELD = "entity_type"; // type of the entity (e.g., dataset, application) | ||
| private static final String NAME_FIELD = "name"; // name of the entity | ||
| private static final String VERSION = "version"; | ||
| private static final String CREATED_FIELD = "creation_time"; // creation-time | ||
| private static final String USER_FIELD = "user"; // USER-scoped properties/tags | ||
| private static final String SYSTEM_FIELD = "system"; // SYSTEM-scoped properties/tags |
There was a problem hiding this comment.
It is okay to remove the line comments here. They are not adding significant value.
| executeDdlStatements(statements); | ||
| LOG.info("metadata and metadata_props dropped successfully."); | ||
| } catch (IOException e) { | ||
| LOG.error("Error dropping index: {}", e.getMessage(), e); |
There was a problem hiding this comment.
no need of extra logger here.
00dade1 to
e90a01c
Compare
updated addressed comments
|


Description:
This PR is the follow-up for #15959 and here we are temporarily building this module separately as a workaround for a dependency issue that breaks the unified build and the unit-tests will be added in the follow-up PRs. It's key changes are listed below:
createIndexhas been implemented along with its helper methods.This change is responsible for the creation of tables in the spanner instance.It also implements thedropIndexmethod which is responsible for dropping the tables in spanner instance.Testing: