Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ package org.lfdecentralizedtrust.splice.store

import cats.data.NonEmptyList
import com.daml.ledger.javaapi.data.codegen.ContractId
import com.daml.nonempty.NonEmpty
import com.digitalasset.canton.config.CantonRequireTypes.String3
import com.digitalasset.canton.logging.NamedLogging
import com.digitalasset.canton.resource.DbStorage
import com.digitalasset.canton.resource.DbStorage.Implicits.BuilderChain.toSQLActionBuilderChain
import org.lfdecentralizedtrust.splice.codegen.java.splice.dsorules.VoteRequest
import org.lfdecentralizedtrust.splice.store.db.AcsQueries.AcsStoreId
Expand Down Expand Up @@ -145,14 +147,14 @@ trait DbVotesAcsStoreQueryBuilder extends AcsQueries with LimitHelpers with Name
acsStoreId: AcsStoreId,
domainMigrationId: Long,
trackingCidColumnName: String,
trackingCids: Seq[VoteRequest.ContractId],
trackingCids: NonEmpty[Seq[VoteRequest.ContractId]],
limit: Limit,
): SqlStreamingAction[Vector[
AcsQueries.SelectFromAcsTableResult
], AcsQueries.SelectFromAcsTableResult, Effect.Read] = {
val cids: Seq[ContractId[?]] = trackingCids
val cids: NonEmpty[Seq[ContractId[?]]] = trackingCids
val voteRequestTrackingCidsSql =
inClause(trackingCidColumnName, cids)
DbStorage.toInClause(trackingCidColumnName, cids)
selectFromAcsTable(
acsTableName,
acsStoreId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.daml.ledger.api.v2.TraceContextOuterClass
import com.daml.ledger.javaapi.data.codegen.{ContractId, DamlRecord}
import com.daml.ledger.javaapi.data.{CreatedEvent, Event, ExercisedEvent, Identifier, Transaction}
import com.daml.metrics.api.MetricsContext
import com.daml.nonempty.NonEmpty
import com.google.protobuf.ByteString
import com.digitalasset.canton.util.HexString
import org.lfdecentralizedtrust.splice.environment.ledger.api.ReassignmentEvent.{Assign, Unassign}
Expand Down Expand Up @@ -1339,33 +1340,33 @@ class UpdateHistory(
private def queryCreateEvents(
transactionRowIds: Seq[Long]
)(implicit tc: TraceContext): Future[Map[Long, Seq[SelectFromCreateEvents]]] = {
if (transactionRowIds.isEmpty) {
Future.successful(Map.empty)
} else {
storage
.query(
(sql"""
select
update_row_id,
event_id,
contract_id,
created_at,
template_id_package_id,
template_id_module_name,
template_id_entity_name,
package_name,
create_arguments,
signatories,
observers,
contract_key,
record_time

from update_history_creates
where """ ++ inClause("update_row_id", transactionRowIds)).toActionBuilder
.as[SelectFromCreateEvents],
"queryCreateEvents",
)
.map(_.groupBy(_.updateRowId))
NonEmpty.from(transactionRowIds) match {
case None => Future.successful(Map.empty)
case Some(transactionRowIds) =>
storage
.query(
(sql"""
select
update_row_id,
event_id,
contract_id,
created_at,
template_id_package_id,
template_id_module_name,
template_id_entity_name,
package_name,
create_arguments,
signatories,
observers,
contract_key,
record_time

from update_history_creates
where """ ++ DbStorage.toInClause("update_row_id", transactionRowIds)).toActionBuilder
.as[SelectFromCreateEvents],
"queryCreateEvents",
)
.map(_.groupBy(_.updateRowId))
}
}

Expand Down Expand Up @@ -1410,35 +1411,35 @@ class UpdateHistory(
private def queryExerciseEvents(
transactionRowIds: Seq[Long]
)(implicit tc: TraceContext): Future[Map[Long, Seq[SelectFromExerciseEvents]]] = {
if (transactionRowIds.isEmpty) {
Future.successful(Map.empty)
} else {
storage
.query(
(sql"""
select
update_row_id,
event_id,
child_event_ids,
choice,
template_id_package_id,
template_id_module_name,
template_id_entity_name,
contract_id,
consuming,
package_name,
argument,
result,
acting_parties,
interface_id_package_id,
interface_id_module_name,
interface_id_entity_name
from update_history_exercises
where """ ++ inClause("update_row_id", transactionRowIds)).toActionBuilder
.as[SelectFromExerciseEvents],
"queryExerciseEvents",
)
.map(_.groupBy(_.updateRowId))
NonEmpty.from(transactionRowIds) match {
case None => Future.successful(Map.empty)
case Some(transactionRowIds) =>
storage
.query(
(sql"""
select
update_row_id,
event_id,
child_event_ids,
choice,
template_id_package_id,
template_id_module_name,
template_id_entity_name,
contract_id,
consuming,
package_name,
argument,
result,
acting_parties,
interface_id_package_id,
interface_id_module_name,
interface_id_entity_name
from update_history_exercises
where """ ++ DbStorage.toInClause("update_row_id", transactionRowIds)).toActionBuilder
.as[SelectFromExerciseEvents],
"queryExerciseEvents",
)
.map(_.groupBy(_.updateRowId))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ import org.lfdecentralizedtrust.splice.store.db.AcsQueries.{
}
import org.lfdecentralizedtrust.splice.store.db.AcsTables.ContractStateRowData
import AsUpdateReturning.*
import com.daml.nonempty.NonEmpty
import com.daml.nonempty.{NonEmpty, NonEmptyUtil}
import com.digitalasset.canton.data.CantonTimestamp
import com.daml.metrics.api.MetricHandle.LabeledMetricsFactory
import com.digitalasset.canton.resource.DbStorage.SQLActionBuilderChain
Expand Down Expand Up @@ -218,22 +218,24 @@ final class DbMultiDomainAcsStore[TXE](
companionClass: ContractCompanion[C, TCid, T],
traceContext: TraceContext,
): Future[Seq[ContractWithState[TCid, T]]] = {
if (ids.isEmpty) Future.successful(Seq.empty)
else {
waitUntilAcsIngested {
storage
.query( // index: acs_store_template_sid_mid_cid
selectFromAcsTableWithState(
acsTableName,
acsStoreId,
domainMigrationId,
companion,
additionalWhere = (sql"and " ++ inClause("acs.contract_id", ids)).toActionBuilder,
),
"lookupContractsById",
)
.map(result => result.map(contractWithStateFromRow(companion)(_)))
}
NonEmpty.from(ids) match {
case None => Future.successful(Seq.empty)
case Some(ids) =>
waitUntilAcsIngested {
storage
.query( // index: acs_store_template_sid_mid_cid
selectFromAcsTableWithState(
acsTableName,
acsStoreId,
domainMigrationId,
companion,
additionalWhere =
(sql"and " ++ DbStorage.toInClause("acs.contract_id", ids)).toActionBuilder,
),
"lookupContractsById",
)
.map(result => result.map(contractWithStateFromRow(companion)(_)))
}
}
}

Expand Down Expand Up @@ -287,25 +289,26 @@ final class DbMultiDomainAcsStore[TXE](
def containsArchived(ids: Seq[ContractId[?]])(implicit
traceContext: TraceContext
): Future[Boolean] = waitUntilAcsIngested {
if (ids.isEmpty) Future.successful(false)
else {
val expectedCount = ids.size
storage
.query(
(sql"""
select count(1)
from #$acsTableName acs
where acs.store_id = $acsStoreId
and acs.migration_id = $domainMigrationId
and """ ++ inClause("acs.contract_id", ids) ++ sql"""
""").toActionBuilder
.as[Int]
.head,
"containsArchived",
)
.map { count =>
count != expectedCount
}
NonEmpty.from(ids) match {
case None => Future.successful(false)
case Some(ids) =>
val expectedCount = ids.size
storage
.query(
(sql"""
select count(1)
from #$acsTableName acs
where acs.store_id = $acsStoreId
and acs.migration_id = $domainMigrationId
and """ ++ DbStorage.toInClause("acs.contract_id", ids) ++ sql"""
""").toActionBuilder
.as[Int]
.head,
"containsArchived",
)
.map { count =>
count != expectedCount
}
}
}

Expand Down Expand Up @@ -1725,18 +1728,21 @@ final class DbMultiDomainAcsStore[TXE](
private def checkIncompleteReassignments(
contractIds: Seq[String]
): DBIOAction[Set[String], NoStream, Effect.Read] = {
if (contractIds.isEmpty) DBIO.successful(Set.empty)
else {
DBIO
.sequence(contractIds.grouped(ingestionConfig.maxLookupsPerStatement).map { contractIds =>
(sql"""
select distinct contract_id from incomplete_reassignments
where store_id = $acsStoreId and migration_id = $domainMigrationId and """ ++ inClause(
"contract_id",
contractIds.map(lengthLimited),
)).toActionBuilder.as[String].map(_.toSet)
})
.map(_.foldLeft(Set.empty[String])(_ ++ _))
NonEmpty.from(contractIds) match {
case None => DBIO.successful(Set.empty)
case Some(contractIds) =>
DBIO
.sequence(contractIds.grouped(ingestionConfig.maxLookupsPerStatement).map {
contractIds =>
(sql"""
select distinct contract_id from incomplete_reassignments
where store_id = $acsStoreId and migration_id = $domainMigrationId and """ ++ DbStorage
.toInClause(
"contract_id",
NonEmptyUtil.fromUnsafe(contractIds.map(lengthLimited)),
)).toActionBuilder.as[String].map(_.toSet)
})
.map(_.foldLeft(Set.empty[String])(_ ++ _))
}
}

Expand Down Expand Up @@ -1929,53 +1935,54 @@ final class DbMultiDomainAcsStore[TXE](
}

private def doDeleteContracts(deletes: Seq[Delete], summary: MutableIngestionSummary) = {
if (deletes.isEmpty) DBIO.successful(())
else {
DBIO.sequence(deletes.grouped(ingestionConfig.maxDeletesPerStatement).map { deletes =>
val performDeleteSql = acsArchiveConfigOpt match {
case Some(AcsArchiveConfig(archiveTableName, baseColumns)) =>
val valuesPairs = deletes.map { d =>
val cid = lengthLimited(d.evt.getContractId)
val archivedAt = CantonTimestamp.assertFromInstant(d.recordTime).toMicros
sql"($cid, $archivedAt)"
}
val valuesClause = sqlCommaSeparated(valuesPairs)
(sql"""
WITH deleted AS (
DELETE FROM #$acsTableName
USING (VALUES """ ++ valuesClause ++ sql""") AS at(cid, archived_at)
WHERE store_id = $acsStoreId
AND migration_id = $domainMigrationId
AND #$acsTableName.contract_id = at.cid
RETURNING #$baseColumns, at.archived_at
)
INSERT INTO #$archiveTableName (#$baseColumns, archived_at)
SELECT * FROM deleted
RETURNING contract_id
""").toActionBuilder.as[String]
case None =>
val contractIds = deletes.map(d => lengthLimited(d.evt.getContractId))
(sql"""DELETE FROM #$acsTableName
WHERE store_id = $acsStoreId
AND migration_id = $domainMigrationId
AND """ ++ inClause(
"contract_id",
contractIds,
) ++ sql" RETURNING contract_id").toActionBuilder
.as[String]
}
NonEmpty.from(deletes) match {
case None => DBIO.successful(())
case Some(deletes) =>
DBIO.sequence(deletes.grouped(ingestionConfig.maxDeletesPerStatement).map { deletes =>
val performDeleteSql = acsArchiveConfigOpt match {
case Some(AcsArchiveConfig(archiveTableName, baseColumns)) =>
val valuesPairs = deletes.map { d =>
val cid = lengthLimited(d.evt.getContractId)
val archivedAt = CantonTimestamp.assertFromInstant(d.recordTime).toMicros
sql"($cid, $archivedAt)"
}
val valuesClause = sqlCommaSeparated(valuesPairs)
(sql"""
WITH deleted AS (
DELETE FROM #$acsTableName
USING (VALUES """ ++ valuesClause ++ sql""") AS at(cid, archived_at)
WHERE store_id = $acsStoreId
AND migration_id = $domainMigrationId
AND #$acsTableName.contract_id = at.cid
RETURNING #$baseColumns, at.archived_at
)
INSERT INTO #$archiveTableName (#$baseColumns, archived_at)
SELECT * FROM deleted
RETURNING contract_id
""").toActionBuilder.as[String]
case None =>
val contractIds = deletes.map(d => lengthLimited(d.evt.getContractId))
(sql"""DELETE FROM #$acsTableName
WHERE store_id = $acsStoreId
AND migration_id = $domainMigrationId
AND """ ++ DbStorage.toInClause(
"contract_id",
NonEmptyUtil.fromUnsafe(contractIds),
) ++ sql" RETURNING contract_id").toActionBuilder
.as[String]
}

performDeleteSql.map { deletedCids =>
val deletedCidSet = deletedCids.toSet
val ingestedArchivedEvents =
deletes.filter(d => deletedCidSet.contains(d.evt.getContractId)).map(_.evt)
summary.ingestedArchivedEvents.addAll(ingestedArchivedEvents)
// there were no contracts with some id. This can happen because:
// `contractFilter.mightContain` in `getIngestionWork` can return true for a template,
// but that might still satisfy some other filter, so the contract was never inserted
summary.numFilteredArchivedEvents += (deletes.length - deletedCids.size)
}
})
performDeleteSql.map { deletedCids =>
val deletedCidSet = deletedCids.toSet
val ingestedArchivedEvents =
deletes.filter(d => deletedCidSet.contains(d.evt.getContractId)).map(_.evt)
summary.ingestedArchivedEvents.addAll(ingestedArchivedEvents)
// there were no contracts with some id. This can happen because:
// `contractFilter.mightContain` in `getIngestionWork` can return true for a template,
// but that might still satisfy some other filter, so the contract was never inserted
summary.numFilteredArchivedEvents += (deletes.length - deletedCids.size)
}
})
}
}

Expand Down
Loading