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
import java.sql.Connection
import javax.inject.Inject
import com.alexitc.playsonify.core.ApplicationResult
import com.alexitc.playsonify.models.ApplicationError
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.models.rpc.Block
import com.xsn.explorer.models.{Address, Balance, Transaction}
import com.xsn.explorer.util.Extensions.ListOptionExt
import javax.inject.Inject
import org.scalactic.Good
import play.api.db.Database
@ -18,7 +18,8 @@ class LedgerPostgresDataHandler @Inject() (
override val database: Database,
blockPostgresDAO: BlockPostgresDAO,
transactionPostgresDAO: TransactionPostgresDAO,
balancePostgresDAO: BalancePostgresDAO)
balancePostgresDAO: BalancePostgresDAO,
aggregatedAmountPostgresDAO: AggregatedAmountPostgresDAO)
extends LedgerBlockingDataHandler
with AnormPostgresDataHandler {
@ -73,10 +74,16 @@ class LedgerPostgresDataHandler @Inject() (
_ <- transactions.map(tx => transactionPostgresDAO.upsert(tx)).everything
// balances
_ <- balances(transactions)
balanceList = balances(transactions)
_ <- balanceList
.map { b => balancePostgresDAO.upsert(b) }
.toList
.everything
// compute aggregated amount
delta = balanceList.map(_.available).sum
_ = aggregatedAmountPostgresDAO.updateAvailableCoins(delta)
} yield ()
// link previous block (if possible)
@ -96,11 +103,16 @@ class LedgerPostgresDataHandler @Inject() (
_ <- blockPostgresDAO.delete(block.hash)
// balances
_ <- balances(deletedTransactions)
balanceList = balances(deletedTransactions)
_ <- balanceList
.map { b => b.copy(spent = -b.spent, received = -b.received) }
.map { b => balancePostgresDAO.upsert(b) }
.toList
.everything
// compute aggregated amount
delta = balanceList.map(_.available).sum
_ = aggregatedAmountPostgresDAO.updateAvailableCoins(-delta)
} 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.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.errors.{PreviousBlockMissingError, RepeatedBlockHeightError}
import com.xsn.explorer.helpers.{BlockLoader, TransactionLoader}
@ -17,7 +17,8 @@ class LedgerPostgresDataHandlerSpec extends PostgresDataHandlerSpec with BeforeA
database,
new BlockPostgresDAO(new FieldOrderingSQLInterpreter),
new TransactionPostgresDAO(new FieldOrderingSQLInterpreter),
new BalancePostgresDAO(new FieldOrderingSQLInterpreter))
new BalancePostgresDAO(new FieldOrderingSQLInterpreter),
new AggregatedAmountPostgresDAO)
val blockList = List(
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.pagination._
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.common.PostgresDataHandlerSpec
import com.xsn.explorer.errors.{BlockNotFoundError, TransactionNotFoundError}
@ -22,7 +22,8 @@ class TransactionPostgresDataHandlerSpec extends PostgresDataHandlerSpec with Be
database,
new BlockPostgresDAO(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))
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.sql.FieldOrderingSQLInterpreter
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.async.{BlockFutureDataHandler, LedgerFutureDataHandler, TransactionFutureDataHandler}
import com.xsn.explorer.data.common.PostgresDataHandlerSpec
@ -24,7 +24,8 @@ class LedgerSynchronizerServiceSpec extends PostgresDataHandlerSpec with BeforeA
database,
new BlockPostgresDAO(new FieldOrderingSQLInterpreter),
new TransactionPostgresDAO(new FieldOrderingSQLInterpreter),
new BalancePostgresDAO(new FieldOrderingSQLInterpreter))
new BalancePostgresDAO(new FieldOrderingSQLInterpreter),
new AggregatedAmountPostgresDAO)
lazy val transactionDataHandler = new TransactionPostgresDataHandler(
database,

Loading…
Cancel
Save