Browse Source

server: Precompute the available coins

In order to speed up the available coins retrieval,
the aggregated_amounts table is created, here we store
the total available coins which can be retrieved fast.
prometheus-integration
Alexis Hernandez 6 years ago
parent
commit
80c7460b18
  1. 22
      server/app/com/xsn/explorer/data/anorm/LedgerPostgresDataHandler.scala
  2. 22
      server/app/com/xsn/explorer/data/anorm/dao/AggregatedAmountPostgresDAO.scala
  3. 17
      server/conf/evolutions/default/8.sql
  4. 5
      server/test/com/xsn/explorer/data/LedgerPostgresDataHandlerSpec.scala
  5. 5
      server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala
  6. 5
      server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala

22
server/app/com/xsn/explorer/data/anorm/LedgerPostgresDataHandler.scala

@ -1,16 +1,16 @@
package com.xsn.explorer.data.anorm package com.xsn.explorer.data.anorm
import java.sql.Connection import java.sql.Connection
import javax.inject.Inject
import com.alexitc.playsonify.core.ApplicationResult import com.alexitc.playsonify.core.ApplicationResult
import com.alexitc.playsonify.models.ApplicationError import com.alexitc.playsonify.models.ApplicationError
import com.xsn.explorer.data.LedgerBlockingDataHandler import com.xsn.explorer.data.LedgerBlockingDataHandler
import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO} import com.xsn.explorer.data.anorm.dao.{AggregatedAmountPostgresDAO, BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO}
import com.xsn.explorer.errors.{PostgresForeignKeyViolationError, PreviousBlockMissingError, RepeatedBlockHeightError} import com.xsn.explorer.errors.{PostgresForeignKeyViolationError, PreviousBlockMissingError, RepeatedBlockHeightError}
import com.xsn.explorer.models.rpc.Block import com.xsn.explorer.models.rpc.Block
import com.xsn.explorer.models.{Address, Balance, Transaction} import com.xsn.explorer.models.{Address, Balance, Transaction}
import com.xsn.explorer.util.Extensions.ListOptionExt import com.xsn.explorer.util.Extensions.ListOptionExt
import javax.inject.Inject
import org.scalactic.Good import org.scalactic.Good
import play.api.db.Database import play.api.db.Database
@ -18,7 +18,8 @@ class LedgerPostgresDataHandler @Inject() (
override val database: Database, override val database: Database,
blockPostgresDAO: BlockPostgresDAO, blockPostgresDAO: BlockPostgresDAO,
transactionPostgresDAO: TransactionPostgresDAO, transactionPostgresDAO: TransactionPostgresDAO,
balancePostgresDAO: BalancePostgresDAO) balancePostgresDAO: BalancePostgresDAO,
aggregatedAmountPostgresDAO: AggregatedAmountPostgresDAO)
extends LedgerBlockingDataHandler extends LedgerBlockingDataHandler
with AnormPostgresDataHandler { with AnormPostgresDataHandler {
@ -73,10 +74,16 @@ class LedgerPostgresDataHandler @Inject() (
_ <- transactions.map(tx => transactionPostgresDAO.upsert(tx)).everything _ <- transactions.map(tx => transactionPostgresDAO.upsert(tx)).everything
// balances // balances
_ <- balances(transactions) balanceList = balances(transactions)
_ <- balanceList
.map { b => balancePostgresDAO.upsert(b) } .map { b => balancePostgresDAO.upsert(b) }
.toList .toList
.everything .everything
// compute aggregated amount
delta = balanceList.map(_.available).sum
_ = aggregatedAmountPostgresDAO.updateAvailableCoins(delta)
} yield () } yield ()
// link previous block (if possible) // link previous block (if possible)
@ -96,11 +103,16 @@ class LedgerPostgresDataHandler @Inject() (
_ <- blockPostgresDAO.delete(block.hash) _ <- blockPostgresDAO.delete(block.hash)
// balances // balances
_ <- balances(deletedTransactions) balanceList = balances(deletedTransactions)
_ <- balanceList
.map { b => b.copy(spent = -b.spent, received = -b.received) } .map { b => b.copy(spent = -b.spent, received = -b.received) }
.map { b => balancePostgresDAO.upsert(b) } .map { b => balancePostgresDAO.upsert(b) }
.toList .toList
.everything .everything
// compute aggregated amount
delta = balanceList.map(_.available).sum
_ = aggregatedAmountPostgresDAO.updateAvailableCoins(-delta)
} yield () } yield ()
} }

22
server/app/com/xsn/explorer/data/anorm/dao/AggregatedAmountPostgresDAO.scala

@ -0,0 +1,22 @@
package com.xsn.explorer.data.anorm.dao
import java.sql.Connection
import anorm._
class AggregatedAmountPostgresDAO {
def updateAvailableCoins(delta: BigDecimal)(implicit conn: Connection): Unit = {
val affectedRows = SQL(
"""
|UPDATE aggregated_amounts
|SET value = value + {delta}
|WHERE name = 'available_coins'
""".stripMargin
).on(
'delta -> delta
).executeUpdate()
require(affectedRows == 1)
}
}

17
server/conf/evolutions/default/8.sql

@ -0,0 +1,17 @@
# --- !Ups
CREATE TABLE aggregated_amounts(
name TEXT NOT NULL,
value AMOUNT_TYPE NOT NULL,
-- constraints
CONSTRAINT aggregated_amounts_name_pk PRIMARY KEY (name)
);
INSERT INTO aggregated_amounts
SELECT 'available_coins' AS name, COALESCE(SUM(received - spent), 0) AS value FROM balances;
# --- !Downs
DROP TABLE aggregated_amounts;

5
server/test/com/xsn/explorer/data/LedgerPostgresDataHandlerSpec.scala

@ -2,7 +2,7 @@ package com.xsn.explorer.data
import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter
import com.xsn.explorer.data.anorm.LedgerPostgresDataHandler import com.xsn.explorer.data.anorm.LedgerPostgresDataHandler
import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO} import com.xsn.explorer.data.anorm.dao.{AggregatedAmountPostgresDAO, BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO}
import com.xsn.explorer.data.common.PostgresDataHandlerSpec import com.xsn.explorer.data.common.PostgresDataHandlerSpec
import com.xsn.explorer.errors.{PreviousBlockMissingError, RepeatedBlockHeightError} import com.xsn.explorer.errors.{PreviousBlockMissingError, RepeatedBlockHeightError}
import com.xsn.explorer.helpers.{BlockLoader, TransactionLoader} import com.xsn.explorer.helpers.{BlockLoader, TransactionLoader}
@ -17,7 +17,8 @@ class LedgerPostgresDataHandlerSpec extends PostgresDataHandlerSpec with BeforeA
database, database,
new BlockPostgresDAO(new FieldOrderingSQLInterpreter), new BlockPostgresDAO(new FieldOrderingSQLInterpreter),
new TransactionPostgresDAO(new FieldOrderingSQLInterpreter), new TransactionPostgresDAO(new FieldOrderingSQLInterpreter),
new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) new BalancePostgresDAO(new FieldOrderingSQLInterpreter),
new AggregatedAmountPostgresDAO)
val blockList = List( val blockList = List(
BlockLoader.get("00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34"), BlockLoader.get("00000c822abdbb23e28f79a49d29b41429737c6c7e15df40d1b1f1b35907ae34"),

5
server/test/com/xsn/explorer/data/TransactionPostgresDataHandlerSpec.scala

@ -3,7 +3,7 @@ package com.xsn.explorer.data
import com.alexitc.playsonify.models.ordering.{FieldOrdering, OrderingCondition} import com.alexitc.playsonify.models.ordering.{FieldOrdering, OrderingCondition}
import com.alexitc.playsonify.models.pagination._ import com.alexitc.playsonify.models.pagination._
import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter
import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO} import com.xsn.explorer.data.anorm.dao.{AggregatedAmountPostgresDAO, BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO}
import com.xsn.explorer.data.anorm.{BlockPostgresDataHandler, LedgerPostgresDataHandler, TransactionPostgresDataHandler} import com.xsn.explorer.data.anorm.{BlockPostgresDataHandler, LedgerPostgresDataHandler, TransactionPostgresDataHandler}
import com.xsn.explorer.data.common.PostgresDataHandlerSpec import com.xsn.explorer.data.common.PostgresDataHandlerSpec
import com.xsn.explorer.errors.{BlockNotFoundError, TransactionNotFoundError} import com.xsn.explorer.errors.{BlockNotFoundError, TransactionNotFoundError}
@ -22,7 +22,8 @@ class TransactionPostgresDataHandlerSpec extends PostgresDataHandlerSpec with Be
database, database,
new BlockPostgresDAO(new FieldOrderingSQLInterpreter), new BlockPostgresDAO(new FieldOrderingSQLInterpreter),
new TransactionPostgresDAO(new FieldOrderingSQLInterpreter), new TransactionPostgresDAO(new FieldOrderingSQLInterpreter),
new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) new BalancePostgresDAO(new FieldOrderingSQLInterpreter),
new AggregatedAmountPostgresDAO)
lazy val blockDataHandler = new BlockPostgresDataHandler(database, new BlockPostgresDAO(new FieldOrderingSQLInterpreter)) lazy val blockDataHandler = new BlockPostgresDataHandler(database, new BlockPostgresDAO(new FieldOrderingSQLInterpreter))
val defaultOrdering = FieldOrdering(TransactionField.Time, OrderingCondition.DescendingOrder) val defaultOrdering = FieldOrdering(TransactionField.Time, OrderingCondition.DescendingOrder)

5
server/test/com/xsn/explorer/services/LedgerSynchronizerServiceSpec.scala

@ -3,7 +3,7 @@ package com.xsn.explorer.services
import com.alexitc.playsonify.core.FutureApplicationResult import com.alexitc.playsonify.core.FutureApplicationResult
import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter import com.alexitc.playsonify.sql.FieldOrderingSQLInterpreter
import com.alexitc.playsonify.validators.PaginatedQueryValidator import com.alexitc.playsonify.validators.PaginatedQueryValidator
import com.xsn.explorer.data.anorm.dao.{BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO} import com.xsn.explorer.data.anorm.dao.{AggregatedAmountPostgresDAO, BalancePostgresDAO, BlockPostgresDAO, TransactionPostgresDAO}
import com.xsn.explorer.data.anorm.{BlockPostgresDataHandler, LedgerPostgresDataHandler, TransactionPostgresDataHandler} import com.xsn.explorer.data.anorm.{BlockPostgresDataHandler, LedgerPostgresDataHandler, TransactionPostgresDataHandler}
import com.xsn.explorer.data.async.{BlockFutureDataHandler, LedgerFutureDataHandler, TransactionFutureDataHandler} import com.xsn.explorer.data.async.{BlockFutureDataHandler, LedgerFutureDataHandler, TransactionFutureDataHandler}
import com.xsn.explorer.data.common.PostgresDataHandlerSpec import com.xsn.explorer.data.common.PostgresDataHandlerSpec
@ -24,7 +24,8 @@ class LedgerSynchronizerServiceSpec extends PostgresDataHandlerSpec with BeforeA
database, database,
new BlockPostgresDAO(new FieldOrderingSQLInterpreter), new BlockPostgresDAO(new FieldOrderingSQLInterpreter),
new TransactionPostgresDAO(new FieldOrderingSQLInterpreter), new TransactionPostgresDAO(new FieldOrderingSQLInterpreter),
new BalancePostgresDAO(new FieldOrderingSQLInterpreter)) new BalancePostgresDAO(new FieldOrderingSQLInterpreter),
new AggregatedAmountPostgresDAO)
lazy val transactionDataHandler = new TransactionPostgresDataHandler( lazy val transactionDataHandler = new TransactionPostgresDataHandler(
database, database,

Loading…
Cancel
Save