Skip to content
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

Shorten node identifier if necessary #153

Merged
merged 1 commit into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ Narayana project [documentation](http://narayana.io/docs/project/index.html).

> To ensure that multiple transaction managers can safely coordinate the same resource managers, each Narayana instance
must be configured with a unique ID. By default, this ID is set to 1. To ensure uniqueness in production, you should
configure the `narayana.transaction-manager-id` property with a different value for each instance of your application.
configure the `narayana.node-identifier` property with a different value for each instance of your application. This value
must not exceed a length of 28 bytes. To ensure that the value is shorten to a valid length by hashing with SHA-224,
configure `narayana.shorten-node-identifier-if-necessary` property to true.

# Using databases

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,14 @@ public class NarayanaProperties {
private String logDir;

/**
* Unique transaction manager id.
* Unique node identifier.
*/
private String transactionManagerId = "1";
private String nodeIdentifier = "1";

/**
* Shorten node identifier if exceed a length of 28 bytes.
*/
private boolean shortenNodeIdentifierIfNecessary = false;

/**
* Enable one phase commit optimization.
Expand Down Expand Up @@ -138,12 +143,30 @@ public void setLogDir(String logDir) {
this.logDir = logDir;
}

@Deprecated(forRemoval = true)
public String getTransactionManagerId() {
return this.transactionManagerId;
return getNodeIdentifier();
}

@Deprecated(forRemoval = true)
public void setTransactionManagerId(String nodeIdentifier) {
setNodeIdentifier(nodeIdentifier);
}

public String getNodeIdentifier() {
return this.nodeIdentifier;
}

public void setNodeIdentifier(String nodeIdentifier) {
this.nodeIdentifier = nodeIdentifier;
}

public boolean isShortenNodeIdentifierIfNecessary() {
return this.shortenNodeIdentifierIfNecessary;
}

public void setTransactionManagerId(String transactionManagerId) {
this.transactionManagerId = transactionManagerId;
public void setShortenNodeIdentifierIfNecessary(boolean shortenNodeIdentifierIfNecessary) {
this.shortenNodeIdentifierIfNecessary = shortenNodeIdentifierIfNecessary;
}

public boolean isOnePhaseCommit() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

package dev.snowdrop.boot.narayana.core.properties;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import com.arjuna.ats.arjuna.common.CoordinatorEnvironmentBean;
Expand All @@ -34,6 +37,8 @@
*/
public class NarayanaPropertiesInitializer implements InitializingBean {

private static final String HASH_ALGORITHM_FOR_SHORTENING = "SHA-224";

private final NarayanaProperties properties;

public NarayanaPropertiesInitializer(NarayanaProperties narayanaProperties) {
Expand All @@ -42,7 +47,7 @@ public NarayanaPropertiesInitializer(NarayanaProperties narayanaProperties) {

@Override
public void afterPropertiesSet() {
setNodeIdentifier(this.properties.getTransactionManagerId());
setNodeIdentifier(this.properties.getNodeIdentifier(), this.properties.isShortenNodeIdentifierIfNecessary());
setXARecoveryNodes(this.properties.getXaRecoveryNodes());
setObjectStoreDir(this.properties.getLogDir());
setCommitOnePhase(this.properties.isOnePhaseCommit());
Expand All @@ -58,14 +63,26 @@ public void afterPropertiesSet() {
setExpiryScanners(this.properties.getExpiryScanners());
}

private void setNodeIdentifier(String nodeIdentifier) {
private void setNodeIdentifier(String nodeIdentifier, boolean shortenNodeIdentifierIfNecessary) {
try {
getPopulator(CoreEnvironmentBean.class).setNodeIdentifier(nodeIdentifier);
} catch (CoreEnvironmentBeanException e) {
if (nodeIdentifier != null
&& nodeIdentifier.getBytes(StandardCharsets.UTF_8).length > 28
&& shortenNodeIdentifierIfNecessary) {
getPopulator(CoreEnvironmentBean.class).setNodeIdentifier(shortenNodeIdentifier(nodeIdentifier));
} else {
getPopulator(CoreEnvironmentBean.class).setNodeIdentifier(nodeIdentifier);
}
} catch (CoreEnvironmentBeanException | NoSuchAlgorithmException e) {
throw new IllegalArgumentException(e);
}
}

private byte[] shortenNodeIdentifier(String nodeIdentifier) throws NoSuchAlgorithmException {
byte[] nodeIdentifierAsBytes = nodeIdentifier.getBytes(StandardCharsets.UTF_8);
MessageDigest messageDigest224 = MessageDigest.getInstance(HASH_ALGORITHM_FOR_SHORTENING);
return messageDigest224.digest(nodeIdentifierAsBytes);
}

private void setXARecoveryNodes(List<String> xaRecoveryNodes) {
if (xaRecoveryNodes.isEmpty()) {
xaRecoveryNodes = List.of(getPopulator(CoreEnvironmentBean.class).getNodeIdentifier());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ void shouldSetDefaultProperties() {
@Test
void shouldSetModifiedProperties() {
NarayanaProperties narayanaProperties = new NarayanaProperties();
narayanaProperties.setTransactionManagerId("test-id-1");
narayanaProperties.setNodeIdentifier("test-id-1");
narayanaProperties.setXaRecoveryNodes(List.of("test-id-1", "test-id-2"));
narayanaProperties.setLogDir("test-dir");
narayanaProperties.setDefaultTimeout(1);
Expand Down Expand Up @@ -161,4 +161,18 @@ void shouldSetModifiedProperties() {
.getExpiryScannerClassNames())
.isEqualTo(List.of("test-scanner-1", "test-scanner-2"));
}

@Test
void shouldSetShortenNodeIdentifier() {
NarayanaProperties narayanaProperties = new NarayanaProperties();
narayanaProperties.setNodeIdentifier("x".repeat(30));

narayanaProperties.setShortenNodeIdentifierIfNecessary(true);
NarayanaPropertiesInitializer narayanaPropertiesInitializer =
new NarayanaPropertiesInitializer(narayanaProperties);
narayanaPropertiesInitializer.afterPropertiesSet();

assertThat(BeanPopulator.getDefaultInstance(CoreEnvironmentBean.class)
.getNodeIdentifierBytes().length).isEqualTo(28);
}
}