mirror of
https://github.com/datahub-project/datahub.git
synced 2025-09-26 17:45:30 +00:00
fix(mysql): modifies hashing and equals behavior for primary keys to match mysql behavior (#13984)
This commit is contained in:
parent
1228f9b1de
commit
c2928a1a6d
@ -303,14 +303,15 @@ public class EbeanAspectDao implements AspectDao, AspectMigrationsDao {
|
|||||||
|
|
||||||
int position = 0;
|
int position = 0;
|
||||||
|
|
||||||
|
List<EbeanAspectV2.PrimaryKey> keyList = new ArrayList<>(keys);
|
||||||
final int totalPageCount = QueryUtils.getTotalPageCount(keys.size(), keysCount);
|
final int totalPageCount = QueryUtils.getTotalPageCount(keys.size(), keysCount);
|
||||||
final List<EbeanAspectV2> finalResult =
|
final List<EbeanAspectV2> finalResult =
|
||||||
batchGetSelectString(new ArrayList<>(keys), keysCount, position, forUpdate);
|
batchGetSelectString(keyList, keysCount, position, forUpdate);
|
||||||
|
|
||||||
while (QueryUtils.hasMore(position, keysCount, totalPageCount)) {
|
while (QueryUtils.hasMore(position, keysCount, totalPageCount)) {
|
||||||
position += keysCount;
|
position += keysCount;
|
||||||
final List<EbeanAspectV2> oneStatementResult =
|
final List<EbeanAspectV2> oneStatementResult =
|
||||||
batchGetSelectString(new ArrayList<>(keys), keysCount, position, forUpdate);
|
batchGetSelectString(keyList, keysCount, position, forUpdate);
|
||||||
finalResult.addAll(oneStatementResult);
|
finalResult.addAll(oneStatementResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@ import jakarta.persistence.Lob;
|
|||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Objects;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.EqualsAndHashCode;
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
@ -43,13 +43,17 @@ public class EbeanAspectV2 extends Model {
|
|||||||
/** Key for an aspect in the table. */
|
/** Key for an aspect in the table. */
|
||||||
@Embeddable
|
@Embeddable
|
||||||
@Getter
|
@Getter
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@EqualsAndHashCode
|
|
||||||
public static class PrimaryKey implements Serializable {
|
public static class PrimaryKey implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
public PrimaryKey(@Nonnull String urn, @Nonnull String aspect, long version) {
|
||||||
|
this.urn = urn.stripTrailing();
|
||||||
|
this.aspect = aspect.stripTrailing();
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Index
|
@Index
|
||||||
@Column(name = URN_COLUMN, length = 500, nullable = false)
|
@Column(name = URN_COLUMN, length = 500, nullable = false)
|
||||||
@ -71,6 +75,27 @@ public class EbeanAspectV2 extends Model {
|
|||||||
public EntityAspectIdentifier toAspectIdentifier() {
|
public EntityAspectIdentifier toAspectIdentifier() {
|
||||||
return new EntityAspectIdentifier(getUrn(), getAspect(), getVersion());
|
return new EntityAspectIdentifier(getUrn(), getAspect(), getVersion());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Custom Equals and Hash code that trims to handle MySQL PAD SPACE:
|
||||||
|
// https://dev.mysql.com/doc/refman/8.4/en/charset-binary-collations.html#charset-binary-collations-trailing-space-comparisons
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PrimaryKey that = (PrimaryKey) o;
|
||||||
|
return version == that.version
|
||||||
|
&& Objects.equals(urn.stripTrailing(), that.urn.stripTrailing())
|
||||||
|
&& Objects.equals(aspect.stripTrailing(), that.aspect.stripTrailing());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(urn.stripTrailing(), aspect.stripTrailing(), version);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nonnull @EmbeddedId @Index protected PrimaryKey key;
|
@Nonnull @EmbeddedId @Index protected PrimaryKey key;
|
||||||
|
@ -70,6 +70,7 @@ import java.util.function.Function;
|
|||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import org.apache.commons.lang3.tuple.Triple;
|
import org.apache.commons.lang3.tuple.Triple;
|
||||||
|
import org.testcontainers.shaded.com.google.common.collect.ImmutableSet;
|
||||||
import org.testng.annotations.BeforeClass;
|
import org.testng.annotations.BeforeClass;
|
||||||
import org.testng.annotations.BeforeMethod;
|
import org.testng.annotations.BeforeMethod;
|
||||||
import org.testng.annotations.Test;
|
import org.testng.annotations.Test;
|
||||||
@ -482,6 +483,40 @@ public class EbeanEntityServiceTest
|
|||||||
"Expected version 0 with systemMeta version 3 accounting for the the collision");
|
"Expected version 0 with systemMeta version 3 accounting for the the collision");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: This is not currently super useful because H2 always treats spaces as significant
|
||||||
|
@Test
|
||||||
|
public void testSystemMetadataDuplicateKeyWhitespace() throws Exception {
|
||||||
|
Urn entityUrn = UrnUtils.getUrn("urn:li:corpuser:duplicateKeyTest");
|
||||||
|
SystemMetadata systemMetadata = AspectGenerationUtils.createSystemMetadata();
|
||||||
|
ChangeItemImpl item =
|
||||||
|
ChangeItemImpl.builder()
|
||||||
|
.urn(entityUrn)
|
||||||
|
.aspectName(STATUS_ASPECT_NAME)
|
||||||
|
.recordTemplate(new Status().setRemoved(true))
|
||||||
|
.systemMetadata(systemMetadata)
|
||||||
|
.auditStamp(TEST_AUDIT_STAMP)
|
||||||
|
.build(TestOperationContexts.emptyActiveUsersAspectRetriever(null));
|
||||||
|
_entityServiceImpl.ingestAspects(
|
||||||
|
opContext,
|
||||||
|
AspectsBatchImpl.builder()
|
||||||
|
.retrieverContext(opContext.getRetrieverContext())
|
||||||
|
.items(List.of(item))
|
||||||
|
.build(opContext),
|
||||||
|
false,
|
||||||
|
true);
|
||||||
|
|
||||||
|
Urn entityUrnWhitespace = UrnUtils.getUrn(entityUrn + " ");
|
||||||
|
Map<Urn, List<EnvelopedAspect>> envelopedAspects =
|
||||||
|
_entityServiceImpl.getLatestEnvelopedAspects(
|
||||||
|
opContext,
|
||||||
|
ImmutableSet.of(entityUrn, entityUrnWhitespace),
|
||||||
|
ImmutableSet.of(STATUS_ASPECT_NAME),
|
||||||
|
false);
|
||||||
|
|
||||||
|
assertEquals(envelopedAspects.get(entityUrn).size(), 1);
|
||||||
|
assertEquals(envelopedAspects.get(entityUrnWhitespace).size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void dataGeneratorThreadingTest() {
|
public void dataGeneratorThreadingTest() {
|
||||||
DataGenerator dataGenerator = new DataGenerator(opContext, _entityServiceImpl);
|
DataGenerator dataGenerator = new DataGenerator(opContext, _entityServiceImpl);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user