Skip to content

Commit

Permalink
Merge pull request #153 from graben/nodeidentifier
Browse files Browse the repository at this point in the history
Shorten node identifier if necessary
  • Loading branch information
geoand committed Jul 15, 2024
2 parents 51b55e4 + 9a2d28e commit 0173487
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 11 deletions.
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);
}
}

0 comments on commit 0173487

Please sign in to comment.