Skip to content

[CDAP-21172] Add Creation/Deletion logic for Metadata Tables #15971

Merged
123-komal merged 1 commit into
developfrom
create_branch
Jun 13, 2025
Merged

[CDAP-21172] Add Creation/Deletion logic for Metadata Tables #15971
123-komal merged 1 commit into
developfrom
create_branch

Conversation

@123-komal

@123-komal 123-komal commented Jun 9, 2025

Copy link
Copy Markdown
Contributor

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:

  • SpannerMetadataStorage: In this PR createIndex has been implemented along with its helper methods.This change is responsible for the creation of tables in the spanner instance.It also implements the dropIndex method which is responsible for dropping the tables in spanner instance.
  • SpannerConfig:This class is responsible for setting up the spanner-related configurations.

Testing:

  • Local Testing:Tested these changes using a Distributed docker image.

@123-komal 123-komal force-pushed the create_branch branch 3 times, most recently from 51d0b07 to ef67afc Compare June 10, 2025 10:57
@123-komal 123-komal changed the title Create branch [CDAP-21172] Implemented createIndex and dropIndex method Jun 10, 2025

@sidhdirenge sidhdirenge left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread cdap-master/pom.xml
Comment on lines +29 to +38
static final String PROJECT = "project";
static final String INSTANCE = "instance";
static final String DATABASE = "database";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we make these fields private?

@123-komal 123-komal Jun 10, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will be using these fields for unit tests so we use them or we can add getter methods for them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
.
.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rename to USER_FIELD

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +64 to +71
private String instanceId = "instance";
private String databaseId = "database";
private String projectId = "project";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we initializing these values?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 this should be configured by cdapmaster

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines +307 to +308
LOG.error("Error executing DDL statements: {}", e.getMessage(), e);
throw new IOException(e);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need of extra logger here - IOException will print the entire stack trace in the logs.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

@Override
public void dropIndex() throws IOException {
throw new IOException("NOT IMPLEMENTED");
synchronized (this) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of synchronization here. You can just silently ignore exception if table does not exist.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okk

statements.add(String.format("DROP TABLE IF EXISTS %s", METADATA_PROPS_TABLE));
try {
executeCreateDDLStatements(statements);
LOG.info("Table dropped successfully.");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logger not very informational - which table was dropped?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

executeCreateDDLStatements(statements);
LOG.info("Table dropped successfully.");
} catch (IOException e) {
LOG.error("Error dropping index: {}", e.getMessage(), e);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need of extra logger here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved

}

/**
* <p>Key features of the schema:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okk

"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",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadata can be replaced with table name defined at the start.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okk

LOG.info("Generating create table DDL statement.");
return String.format(
"CREATE TABLE IF NOT EXISTS %s (" +
"Metadata_ID STRING(MAX) NOT NULL," +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadata_id can also be defined as another constant with field name.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okk

"%s STRING(MAX)," + // system
"metadata_column JSON," + // metadata
"VERSION INT64 NOT NULL," +
"User_Tokens TOKENLIST AS " +

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

column names should always be -> user_tokens, system_tokens, text_tokens

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okk

}
return cConf.get(PROJECT);
}
} No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add new line

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@@ -16,6 +16,15 @@

package io.cdap.cdap.metadata.spanner;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add test file for this class?

cc @sidhdirenge

String instance = cConf.get(DATABASE);
if (instance == null) {
throw new IllegalArgumentException("Missing configuration " + DATABASE);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

}

static String getProjectID(Map<String, String> cConf) {
String instance = cConf.get(PROJECT);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • 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?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated

if (created) {
return;
}
synchronized (this) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@123-komal 123-komal force-pushed the create_branch branch 7 times, most recently from 94e5d3b to f0b7cc5 Compare June 11, 2025 08:55
@123-komal 123-komal changed the title [CDAP-21172] Implemented createIndex and dropIndex method [CDAP-21172] Implement createIndex and dropIndex method Jun 11, 2025
Comment on lines +54 to +62
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is okay to remove the line comments here. They are not adding significant value.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okk

executeDdlStatements(statements);
LOG.info("metadata and metadata_props dropped successfully.");
} catch (IOException e) {
LOG.error("Error dropping index: {}", e.getMessage(), e);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need of extra logger here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okk

@123-komal 123-komal changed the title [CDAP-21172] Implement createIndex and dropIndex method [CDAP-21172] Add Creation/Deletion logic for Metadata Tables Jun 11, 2025
@123-komal 123-komal force-pushed the create_branch branch 4 times, most recently from 00dade1 to e90a01c Compare June 12, 2025 13:08
@123-komal 123-komal added build Triggers github actions build labels Jun 13, 2025
@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@123-komal 123-komal merged commit f558b98 into develop Jun 13, 2025
22 of 25 checks passed
@123-komal 123-komal deleted the create_branch branch June 13, 2025 12:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

build Triggers github actions build

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants