Skip to content

Commit

Permalink
Fix token_account primary index (#1424)
Browse files Browse the repository at this point in the history
* Fix token_account primary index

#1364 updated the token_account table to have a primary index on the timestamp.
However, an account can be associated with multiple tokens in a single TokenAssociate transaction.

- Update `V1.33.0__drop_token_account_id.sql` migration file to set `token_account` primary index to use `created_timestamp, token_id`
- Update `V2.0.2__time_scale_index_init.sql` file to set `token_account` primary index to use `created_timestamp, token_id`
- Update `TokenAccountRepositoryTest` with test to capture scenario

Signed-off-by: Nana-EC <[email protected]>
  • Loading branch information
Nana-EC authored Jan 8, 2021
1 parent f574a21 commit 2d8155d
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
alter table if exists token_account
drop constraint token_account_pkey;
alter table if exists token_account
add primary key (created_timestamp);
add primary key (created_timestamp, token_id);
alter table if exists token_account
drop column if exists id;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ create unique index if not exists token__id_timestamp

-- token_account
alter table token_account
add primary key (created_timestamp);
add primary key (created_timestamp, token_id);
create unique index if not exists token_account__token_account_timestamp
on token_account (token_id, account_id, created_timestamp);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ alter table token
set (timescaledb.compress, timescaledb.compress_segmentby = 'token_id');

alter table token_account
set (timescaledb.compress, timescaledb.compress_segmentby = 'account_id');
set (timescaledb.compress, timescaledb.compress_segmentby = 'token_id');

alter table token_balance
set (timescaledb.compress, timescaledb.compress_segmentby = 'account_id, token_id');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import com.hedera.mirror.importer.domain.LiveHash;
import com.hedera.mirror.importer.domain.NonFeeTransfer;
import com.hedera.mirror.importer.domain.RecordFile;
import com.hedera.mirror.importer.domain.StreamFileData;
import com.hedera.mirror.importer.domain.Token;
import com.hedera.mirror.importer.domain.TokenAccount;
import com.hedera.mirror.importer.domain.TokenFreezeStatusEnum;
Expand All @@ -56,7 +57,6 @@
import com.hedera.mirror.importer.domain.Transaction;
import com.hedera.mirror.importer.domain.TransactionTypeEnum;
import com.hedera.mirror.importer.exception.MissingFileException;
import com.hedera.mirror.importer.domain.StreamFileData;
import com.hedera.mirror.importer.repository.ContractResultRepository;
import com.hedera.mirror.importer.repository.CryptoTransferRepository;
import com.hedera.mirror.importer.repository.EntityRepository;
Expand Down Expand Up @@ -240,7 +240,7 @@ void onEntityIdDuplicates() throws Exception {
sqlEntityListener.onEntityId(entityId); // duplicate within file
completeFileAndCommit();

recordFile = insertRecordFileRecord(UUID.randomUUID().toString(), null, null, 1L);
recordFile = insertRecordFileRecord(UUID.randomUUID().toString(), null, null, 2L);
sqlEntityListener.onStart(new StreamFileData(fileName, null));
sqlEntityListener.onEntityId(entityId); // duplicate across files
completeFileAndCommit();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package com.hedera.mirror.importer.repository;

import java.util.Optional;
import javax.annotation.Resource;
import org.apache.commons.codec.DecoderException;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;

Expand All @@ -16,33 +14,55 @@ public class TokenAccountRepositoryTest extends AbstractRepositoryTest {
@Resource
protected TokenAccountRepository tokenAccountRepository;

private final EntityId tokenId = EntityId.of("0.0.101", EntityTypeEnum.TOKEN);
private final EntityId accountId = EntityId.of("0.0.102", EntityTypeEnum.ACCOUNT);
private final String tokenId = "0.0.101";
private final String accountId = "0.0.102";

@Test
void save() throws DecoderException {
TokenAccount token = tokenAccountRepository.save(tokenAccount("0.0.101", "0.0.102", 1));
void save() {
TokenAccount token = tokenAccountRepository.save(tokenAccount(tokenId, accountId, 1));
Assertions.assertThat(tokenAccountRepository.findById(token.getId()).get())
.isNotNull()
.isEqualTo(token);
}

@Test
void findByTokenIdAndAccountId() throws DecoderException {
tokenAccountRepository.save(tokenAccount("0.0.101", "0.0.102", 1));
String tokenId = "0.2.22";
String accountId = "0.2.44";
TokenAccount token2 = tokenAccountRepository.save(tokenAccount(tokenId, accountId, 2));
void findByTokenIdAndAccountId() {
tokenAccountRepository.save(tokenAccount(tokenId, accountId, 1));
String tokenId2 = "0.2.22";
String accountId2 = "0.2.44";
TokenAccount token2 = tokenAccountRepository.save(tokenAccount(tokenId2, accountId2, 2));
tokenAccountRepository.save(tokenAccount("1.0.7", "1.0.34", 3));
Assertions.assertThat(tokenAccountRepository
.findByTokenIdAndAccountId(EntityId.of(tokenId, EntityTypeEnum.TOKEN).getId(), EntityId
.of(accountId, EntityTypeEnum.ACCOUNT).getId()).get())
.findByTokenIdAndAccountId(EntityId.of(tokenId2, EntityTypeEnum.TOKEN).getId(), EntityId
.of(accountId2, EntityTypeEnum.ACCOUNT).getId()).get())
.isNotNull()
.isEqualTo(token2);

Assertions.assertThat(tokenAccountRepository
.findByTokenIdAndAccountId(EntityId.of("1.2.3", EntityTypeEnum.TOKEN).getId(), EntityId
.of("0.2.44", EntityTypeEnum.ACCOUNT).getId())).isEqualTo(Optional.empty());
.of("0.2.44", EntityTypeEnum.ACCOUNT).getId())).isNotPresent();
}

@Test
void findByTokenIdAndAccountIdMultipleTokensSameAccount() {
String tokenId2 = "0.2.22";
String accountId2 = "0.0.44";
long createTimestamp1 = 55;
long createTimestamp2 = 66;
tokenAccountRepository.save(tokenAccount(tokenId, accountId, createTimestamp1));
tokenAccountRepository
.save(tokenAccount(tokenId, accountId, createTimestamp2));
TokenAccount tokenAccount_1_2 = tokenAccountRepository
.save(tokenAccount(tokenId2, accountId, createTimestamp2));
Assertions.assertThat(tokenAccountRepository
.findByTokenIdAndAccountId(EntityId.of(tokenId2, EntityTypeEnum.TOKEN).getId(), EntityId
.of(accountId, EntityTypeEnum.ACCOUNT).getId()).get())
.isNotNull()
.isEqualTo(tokenAccount_1_2);

Assertions.assertThat(tokenAccountRepository
.findByTokenIdAndAccountId(EntityId.of(tokenId2, EntityTypeEnum.TOKEN).getId(), EntityId
.of(accountId2, EntityTypeEnum.ACCOUNT).getId())).isNotPresent();
}

private TokenAccount tokenAccount(String tokenId, String accountId, long createdTimestamp) {
Expand Down

0 comments on commit 2d8155d

Please sign in to comment.