Починить восстановление blockchain_state при full resync
This commit is contained in:
parent
d49661fa29
commit
44a1ba01f3
@ -159,6 +159,7 @@ Full resync запускается только тогда, когда:
|
|||||||
- настройка `sync.importUserProfileFromPartner.enabled=true`
|
- настройка `sync.importUserProfileFromPartner.enabled=true`
|
||||||
- в этом режиме сервер **не ходит в Solana RPC** для создания локальной цепочки во время sync;
|
- в этом режиме сервер **не ходит в Solana RPC** для создания локальной цепочки во время sync;
|
||||||
- вместо этого он запрашивает у сервера-партнёра `GetSyncUserProfile` и создаёт локальную запись по данным партнёра.
|
- вместо этого он запрашивает у сервера-партнёра `GetSyncUserProfile` и создаёт локальную запись по данным партнёра.
|
||||||
|
- если локальный `solana_users` уже существует, sync восстанавливает только `blockchain_state` и не трогает identity-слой.
|
||||||
|
|
||||||
Это временная практическая заплатка, чтобы clean-start sync не зависел от rate limit внешнего Solana endpoint.
|
Это временная практическая заплатка, чтобы clean-start sync не зависел от rate limit внешнего Solana endpoint.
|
||||||
|
|
||||||
|
|||||||
@ -138,6 +138,54 @@ public final class BlockchainStateDAO {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Строгая вставка state только если записи ещё нет.
|
||||||
|
*
|
||||||
|
* Нужна для recovery / resync:
|
||||||
|
* - identity пользователя уже может существовать в solana_users;
|
||||||
|
* - в таком случае нам надо восстановить только blockchain_state;
|
||||||
|
* - если запись уже есть, метод просто ничего не меняет.
|
||||||
|
*/
|
||||||
|
public boolean insertIfMissing(Connection c, BlockchainStateEntry e) throws SQLException {
|
||||||
|
String sql = """
|
||||||
|
INSERT INTO blockchain_state (
|
||||||
|
blockchain_name,
|
||||||
|
login,
|
||||||
|
blockchain_key,
|
||||||
|
size_limit,
|
||||||
|
file_size_bytes,
|
||||||
|
last_block_number,
|
||||||
|
last_block_hash,
|
||||||
|
updated_at_ms
|
||||||
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
|
ON CONFLICT(blockchain_name) DO NOTHING
|
||||||
|
""";
|
||||||
|
|
||||||
|
try (PreparedStatement ps = c.prepareStatement(sql)) {
|
||||||
|
int i = 1;
|
||||||
|
|
||||||
|
ps.setString(i++, e.getBlockchainName());
|
||||||
|
ps.setString(i++, nn(e.getLogin()));
|
||||||
|
ps.setString(i++, nn(e.getBlockchainKey()));
|
||||||
|
|
||||||
|
ps.setLong(i++, e.getSizeLimit());
|
||||||
|
ps.setLong(i++, e.getFileSizeBytes());
|
||||||
|
|
||||||
|
ps.setInt(i++, e.getLastBlockNumber());
|
||||||
|
setBytesNullable(ps, i++, e.getLastBlockHash());
|
||||||
|
|
||||||
|
ps.setLong(i++, e.getUpdatedAtMs());
|
||||||
|
|
||||||
|
return ps.executeUpdate() > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insertIfMissing(BlockchainStateEntry e) throws SQLException {
|
||||||
|
try (Connection c = db.getConnection()) {
|
||||||
|
return insertIfMissing(c, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Атомарно увеличить file_size_bytes на deltaBytes, но только если НЕ превысим size_limit.
|
* Атомарно увеличить file_size_bytes на deltaBytes, но только если НЕ превысим size_limit.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import shine.db.dao.BlockchainResyncCleanupDAO;
|
|||||||
import shine.db.dao.BlockchainStateDAO;
|
import shine.db.dao.BlockchainStateDAO;
|
||||||
import shine.db.dao.SyncServersDAO;
|
import shine.db.dao.SyncServersDAO;
|
||||||
import shine.db.dao.UserCreateDAO;
|
import shine.db.dao.UserCreateDAO;
|
||||||
|
import shine.db.dao.SolanaUsersDAO;
|
||||||
import shine.db.entities.BlockchainStateEntry;
|
import shine.db.entities.BlockchainStateEntry;
|
||||||
import shine.db.entities.SyncServerEntry;
|
import shine.db.entities.SyncServerEntry;
|
||||||
import server.sync.BlockchainResyncGuard;
|
import server.sync.BlockchainResyncGuard;
|
||||||
@ -55,6 +56,7 @@ public final class PeriodicBlockchainSyncService {
|
|||||||
private static final UserCreateDAO USER_CREATE_DAO = UserCreateDAO.getInstance();
|
private static final UserCreateDAO USER_CREATE_DAO = UserCreateDAO.getInstance();
|
||||||
private static final BlockchainResyncCleanupDAO RESYNC_CLEANUP_DAO = BlockchainResyncCleanupDAO.getInstance();
|
private static final BlockchainResyncCleanupDAO RESYNC_CLEANUP_DAO = BlockchainResyncCleanupDAO.getInstance();
|
||||||
private static final FileStoreUtil FILE_STORE = FileStoreUtil.getInstance();
|
private static final FileStoreUtil FILE_STORE = FileStoreUtil.getInstance();
|
||||||
|
private static final SolanaUsersDAO SOLANA_USERS_DAO = SolanaUsersDAO.getInstance();
|
||||||
private static final String CONFIG_IMPORT_PROFILE_FROM_PARTNER = "sync.importUserProfileFromPartner.enabled";
|
private static final String CONFIG_IMPORT_PROFILE_FROM_PARTNER = "sync.importUserProfileFromPartner.enabled";
|
||||||
|
|
||||||
private PeriodicBlockchainSyncService() {}
|
private PeriodicBlockchainSyncService() {}
|
||||||
@ -386,6 +388,13 @@ public final class PeriodicBlockchainSyncService {
|
|||||||
|
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
long sizeLimit = profile.blockchainSizeLimitBytes() > 0 ? profile.blockchainSizeLimitBytes() : 100_000L;
|
long sizeLimit = profile.blockchainSizeLimitBytes() > 0 ? profile.blockchainSizeLimitBytes() : 100_000L;
|
||||||
|
BlockchainStateEntry state = buildStateFromProfile(profile, sizeLimit, now);
|
||||||
|
|
||||||
|
if (SOLANA_USERS_DAO.existsByLogin(profile.login())) {
|
||||||
|
STATE_DAO.insertIfMissing(state);
|
||||||
|
return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
boolean inserted = USER_CREATE_DAO.insertUserWithBlockchain(
|
boolean inserted = USER_CREATE_DAO.insertUserWithBlockchain(
|
||||||
profile.login(),
|
profile.login(),
|
||||||
profile.blockchainName(),
|
profile.blockchainName(),
|
||||||
@ -396,10 +405,33 @@ public final class PeriodicBlockchainSyncService {
|
|||||||
now
|
now
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!inserted) {
|
if (inserted) {
|
||||||
return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null;
|
return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null;
|
||||||
}
|
}
|
||||||
return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null;
|
|
||||||
|
// Если пользователь уже успел существовать локально, но chain_state отсутствует,
|
||||||
|
// добиваем только state и не пытаемся пересоздать identity.
|
||||||
|
if (SOLANA_USERS_DAO.existsByLogin(profile.login())) {
|
||||||
|
STATE_DAO.insertIfMissing(state);
|
||||||
|
return STATE_DAO.getByBlockchainName(profile.blockchainName()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BlockchainStateEntry buildStateFromProfile(RemoteBlockchainSyncClient.RemoteSyncUserProfile profile,
|
||||||
|
long sizeLimit,
|
||||||
|
long nowMs) {
|
||||||
|
BlockchainStateEntry state = new BlockchainStateEntry();
|
||||||
|
state.setBlockchainName(profile.blockchainName());
|
||||||
|
state.setLogin(profile.login());
|
||||||
|
state.setBlockchainKey(profile.blockchainKey());
|
||||||
|
state.setSizeLimit(sizeLimit);
|
||||||
|
state.setFileSizeBytes(0L);
|
||||||
|
state.setLastBlockNumber(-1);
|
||||||
|
state.setLastBlockHash(null);
|
||||||
|
state.setUpdatedAtMs(nowMs);
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String normalize(String value) {
|
private static String normalize(String value) {
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
client.version=1.2.277
|
client.version=1.2.278
|
||||||
server.version=1.2.257
|
server.version=1.2.258
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user