class TrimService {

    public void doTrimDerivedTablesOnBlockchainHeight(int blockchainHeight, boolean async) {
        log.debug("TRIM: doTrimDerivedTablesOnBlockchainHeight on height {} as async operation (? = {})", blockchainHeight, async);
        lock.lock();
        try {
            int trimHeight = Math.max(blockchainHeight - maxRollback, 0);
            if (trimHeight > 0) {
                TrimEntry trimEntry = trimDao.get();
                if (trimEntry == null || !trimEntry.isDone() || trimEntry.getHeight() < blockchainHeight) {
                    if (trimEntry == null || trimEntry.getHeight() < blockchainHeight) {
                        trimEntry = new TrimEntry(null, blockchainHeight, false);
                    }
                    trimDao.clear();
                    trimEntry = trimDao.save(trimEntry);
                    dbManager.getDataSource().commit(false);
                    int pruningTime = doTrimDerivedTablesOnHeight(trimHeight, false);
                    if (async) {
                        log.debug("Fire doTrimDerived event height '{}' Async, trimHeight={}", blockchainHeight, trimHeight);
                        trimEvent.select(new AnnotationLiteral<TrimEvent>() {
                        }).fireAsync(new TrimData(trimHeight, blockchainHeight, pruningTime));
                    } else {
                        log.debug("Fire doTrimDerived event height '{}' Sync, trimHeight={}", blockchainHeight, trimHeight);
                        trimEvent.select(new AnnotationLiteral<TrimEvent>() {
                        }).fire(new TrimData(trimHeight, blockchainHeight, pruningTime));
                    }
                    trimEntry.setDone(true);
                    trimDao.save(trimEntry);
                    log.debug("doTrimDerived saved {} at height '{}'", trimEntry, blockchainHeight);
                } else {
                    log.debug("doTrimDerived skipped at blockchain height={} and trim height={}", blockchainHeight, trimHeight);
                }
            }
        } finally {
            lock.unlock();
        }
    }

    @Inject public  TrimService(DatabaseManager databaseManager,
                       DerivedTablesRegistry derivedDbTablesRegistry,
                       GlobalSync globalSync,
                       TimeService timeService,
                       Event<TrimData> trimEvent,
                       Event<TrimConfig> trimConfigEvent,
                       TrimDao trimDao,
                       @Property(value = "apl.maxRollback", defaultValue = "720") int maxRollback
    );

}