Skip to content

Commit

Permalink
server: Precompute the available coins
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AlexITC committed Dec 26, 2018
1 parent 73943f7 commit 80c7460
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 11 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
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

class LedgerPostgresDataHandler @Inject() (
override val database: Database,
blockPostgresDAO: BlockPostgresDAO,
transactionPostgresDAO: TransactionPostgresDAO,
balancePostgresDAO: BalancePostgresDAO)
balancePostgresDAO: BalancePostgresDAO,
aggregatedAmountPostgresDAO: AggregatedAmountPostgresDAO)
extends LedgerBlockingDataHandler
with AnormPostgresDataHandler {

Expand Down Expand Up @@ -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)
Expand All @@ -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 ()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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 changes: 17 additions & 0 deletions server/conf/evolutions/default/8.sql
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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,
Expand Down

0 comments on commit 80c7460

Please sign in to comment.