mirror of
https://github.com/Qortal/qortal.git
synced 2025-07-22 20:26:50 +00:00
Rip out historic account balances as they take up too much DB space.
This commit is contained in:
@@ -53,8 +53,8 @@ public class Account {
|
||||
|
||||
// Balance manipulations - assetId is 0 for QORT
|
||||
|
||||
public BigDecimal getBalance(long assetId, int height) throws DataException {
|
||||
AccountBalanceData accountBalanceData = this.repository.getAccountRepository().getBalance(this.address, assetId, height);
|
||||
public BigDecimal getBalance(long assetId) throws DataException {
|
||||
AccountBalanceData accountBalanceData = this.repository.getAccountRepository().getBalance(this.address, assetId);
|
||||
if (accountBalanceData == null)
|
||||
return BigDecimal.ZERO.setScale(8);
|
||||
|
||||
|
@@ -192,7 +192,7 @@ public class AddressesResource {
|
||||
@Path("/balance/{address}")
|
||||
@Operation(
|
||||
summary = "Returns account balance",
|
||||
description = "Returns account's balance, optionally of given asset and at given height",
|
||||
description = "Returns account's QORT balance, or of other specified asset",
|
||||
responses = {
|
||||
@ApiResponse(
|
||||
description = "the balance",
|
||||
@@ -202,8 +202,7 @@ public class AddressesResource {
|
||||
)
|
||||
@ApiErrors({ApiError.INVALID_ADDRESS, ApiError.INVALID_ASSET_ID, ApiError.INVALID_HEIGHT, ApiError.REPOSITORY_ISSUE})
|
||||
public BigDecimal getBalance(@PathParam("address") String address,
|
||||
@QueryParam("assetId") Long assetId,
|
||||
@QueryParam("height") Integer height) {
|
||||
@QueryParam("assetId") Long assetId) {
|
||||
if (!Crypto.isValidAddress(address))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ADDRESS);
|
||||
|
||||
@@ -215,12 +214,7 @@ public class AddressesResource {
|
||||
else if (!repository.getAssetRepository().assetExists(assetId))
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_ASSET_ID);
|
||||
|
||||
if (height == null)
|
||||
height = repository.getBlockRepository().getBlockchainHeight();
|
||||
else if (height <= 0)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.INVALID_HEIGHT);
|
||||
|
||||
return account.getBalance(assetId, height);
|
||||
return account.getBalance(assetId);
|
||||
} catch (ApiException e) {
|
||||
throw e;
|
||||
} catch (DataException e) {
|
||||
|
@@ -1466,9 +1466,6 @@ public class Block {
|
||||
decreaseAccountLevels();
|
||||
}
|
||||
|
||||
// Delete orphaned balances
|
||||
this.repository.getAccountRepository().deleteBalancesFromHeight(this.blockData.getHeight());
|
||||
|
||||
// Delete block from blockchain
|
||||
this.repository.getBlockRepository().delete(this.blockData);
|
||||
this.blockData.setHeight(null);
|
||||
|
@@ -96,12 +96,6 @@ public interface AccountRepository {
|
||||
|
||||
public AccountBalanceData getBalance(String address, long assetId) throws DataException;
|
||||
|
||||
/** Returns account balance data for address & assetId at (or before) passed block height. */
|
||||
public AccountBalanceData getBalance(String address, long assetId, int height) throws DataException;
|
||||
|
||||
/** Returns per-height historic balance for address & assetId. */
|
||||
public List<AccountBalanceData> getHistoricBalances(String address, long assetId) throws DataException;
|
||||
|
||||
public enum BalanceOrdering {
|
||||
ASSET_BALANCE_ACCOUNT,
|
||||
ACCOUNT_ASSET,
|
||||
@@ -118,9 +112,6 @@ public interface AccountRepository {
|
||||
|
||||
public void delete(String address, long assetId) throws DataException;
|
||||
|
||||
/** Deletes orphaned balances at block height >= <tt>height</tt>. */
|
||||
public int deleteBalancesFromHeight(int height) throws DataException;
|
||||
|
||||
// Reward-shares
|
||||
|
||||
public RewardShareData getRewardShare(byte[] mintingAccountPublicKey, String recipientAccount) throws DataException;
|
||||
|
@@ -327,44 +327,6 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccountBalanceData getBalance(String address, long assetId, int height) throws DataException {
|
||||
String sql = "SELECT IFNULL(balance, 0) FROM HistoricAccountBalances WHERE account = ? AND asset_id = ? AND height <= ? ORDER BY height DESC LIMIT 1";
|
||||
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, address, assetId, height)) {
|
||||
if (resultSet == null)
|
||||
return null;
|
||||
|
||||
BigDecimal balance = resultSet.getBigDecimal(1).setScale(8);
|
||||
|
||||
return new AccountBalanceData(address, assetId, balance);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch account balance from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccountBalanceData> getHistoricBalances(String address, long assetId) throws DataException {
|
||||
String sql = "SELECT height, balance FROM HistoricAccountBalances WHERE account = ? AND asset_id = ? ORDER BY height DESC";
|
||||
|
||||
List<AccountBalanceData> historicBalances = new ArrayList<>();
|
||||
try (ResultSet resultSet = this.repository.checkedExecute(sql, address, assetId)) {
|
||||
if (resultSet == null)
|
||||
return historicBalances;
|
||||
|
||||
do {
|
||||
int height = resultSet.getInt(1);
|
||||
BigDecimal balance = resultSet.getBigDecimal(2);
|
||||
|
||||
historicBalances.add(new AccountBalanceData(address, assetId, balance, height));
|
||||
} while (resultSet.next());
|
||||
|
||||
return historicBalances;
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to fetch historic account balances from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AccountBalanceData> getAssetBalances(long assetId, Boolean excludeZero) throws DataException {
|
||||
StringBuilder sql = new StringBuilder(1024);
|
||||
@@ -510,19 +472,6 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to reduce account balance in repository", e);
|
||||
}
|
||||
|
||||
// If balance is now zero, and there are no prior historic balances, then simply delete row for this address-assetId (typically during orphaning)
|
||||
String deleteWhereSql = "account = ? AND asset_id = ? AND balance = 0 " + // covers "if balance now zero"
|
||||
"AND (" +
|
||||
"SELECT TRUE FROM HistoricAccountBalances " +
|
||||
"WHERE account = ? AND asset_id = ? AND height < (SELECT height - 1 FROM NextBlockHeight) " +
|
||||
"LIMIT 1" +
|
||||
")";
|
||||
try {
|
||||
this.repository.delete("AccountBalances", deleteWhereSql, address, assetId, address, assetId);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to prune account balance in repository", e);
|
||||
}
|
||||
} else {
|
||||
// We have to ensure parent row exists to satisfy foreign key constraint
|
||||
try {
|
||||
@@ -545,47 +494,12 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
||||
|
||||
@Override
|
||||
public void save(AccountBalanceData accountBalanceData) throws DataException {
|
||||
// If balance is zero and there are no prior historic balance, then simply delete balances for this assetId (typically during orphaning)
|
||||
if (accountBalanceData.getBalance().signum() == 0) {
|
||||
String existsSql = "account = ? AND asset_id = ? AND height < (SELECT height - 1 FROM NextBlockHeight)"; // height prior to current block. no matches (obviously) prior to genesis block
|
||||
|
||||
boolean hasPriorBalances;
|
||||
try {
|
||||
hasPriorBalances = this.repository.exists("HistoricAccountBalances", existsSql, accountBalanceData.getAddress(), accountBalanceData.getAssetId());
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to check for historic account balances in repository", e);
|
||||
}
|
||||
|
||||
if (!hasPriorBalances) {
|
||||
try {
|
||||
this.repository.delete("AccountBalances", "account = ? AND asset_id = ?", accountBalanceData.getAddress(), accountBalanceData.getAssetId());
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete account balance from repository", e);
|
||||
}
|
||||
|
||||
/*
|
||||
* I don't think we need to do this as Block.orphan() would do this for us?
|
||||
|
||||
try {
|
||||
this.repository.delete("HistoricAccountBalances", "account = ? AND asset_id = ?", accountBalanceData.getAddress(), accountBalanceData.getAssetId());
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete historic account balances from repository", e);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
HSQLDBSaver saveHelper = new HSQLDBSaver("AccountBalances");
|
||||
|
||||
saveHelper.bind("account", accountBalanceData.getAddress()).bind("asset_id", accountBalanceData.getAssetId()).bind("balance",
|
||||
accountBalanceData.getBalance());
|
||||
|
||||
try {
|
||||
// HistoricAccountBalances auto-updated via trigger
|
||||
|
||||
saveHelper.execute(this.repository);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to save account balance into repository", e);
|
||||
@@ -599,21 +513,6 @@ public class HSQLDBAccountRepository implements AccountRepository {
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete account balance from repository", e);
|
||||
}
|
||||
|
||||
try {
|
||||
this.repository.delete("HistoricAccountBalances", "account = ? AND asset_id = ?", address, assetId);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete historic account balances from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteBalancesFromHeight(int height) throws DataException {
|
||||
try {
|
||||
return this.repository.delete("HistoricAccountBalances", "height >= ?", height);
|
||||
} catch (SQLException e) {
|
||||
throw new DataException("Unable to delete historic account balances from repository", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Reward-Share
|
||||
|
@@ -956,6 +956,16 @@ public class HSQLDBDatabaseUpdates {
|
||||
stmt.execute("SET FILES WRITE DELAY 5"); // only fsync() every 5 seconds
|
||||
break;
|
||||
|
||||
case 69:
|
||||
// Get rid of historic account balances as they simply use up way too much space
|
||||
stmt.execute("DROP TRIGGER Historic_Account_Balance_Insert_Trigger");
|
||||
stmt.execute("DROP TRIGGER Historic_Account_Balance_Update_Trigger");
|
||||
stmt.execute("DROP TABLE HistoricAccountBalances");
|
||||
// Reclaim space
|
||||
stmt.execute("CHECKPOINT");
|
||||
stmt.execute("CHECKPOINT DEFRAG");
|
||||
break;
|
||||
|
||||
default:
|
||||
// nothing to do
|
||||
return false;
|
||||
|
Reference in New Issue
Block a user