Use the data control tool from a Legacy Groovy worker
The data control tool (dhctl
) is a command-line tool that allows you to manage data in Deephaven. This functionality is also available from any Legacy worker with sufficient permissions.
Truncate and delete intraday partitions
A builder, described below, provides full control over parameters. For simplicity, some simple options can be invoked via helper methods. These methods do not allow for dry runs or the selection of which Data Import Servers are included.
import io.deephaven.configuration.IntradayControlImpl
// truncate the location(s) specified by the key
IntradayControlImpl.truncateIntradayPartition(FullTableLocationKey)
// truncate the partitions for this table and column partition value (like --partitions)
IntradayControlImpl.truncateIntradayPartition(namespace, tableName, columnPartitionValue)
// truncate the single partition for this table and partition values (like --singlePartition)
IntradayControlImpl.truncateIntradayPartition(namespace, tableName, internalPartitionValue, columnPartitionValue)
// truncate partition(s) as indicated by the options argument (see Options Builder below)
IntradayControlImpl.truncateIntradayPartition(options)
// delete the location(s) specified by the key
IntradayControlImpl.deleteIntradayPartition(FullTableLocationKey)
// delete the partitions for this table and column partition value (like --partitions)
IntradayControlImpl.deleteIntradayPartition(namespace, tableName, columnPartitionValue)
// delete the single partition for this table and partition values (like --singlePartition)
IntradayControlImpl.deleteIntradayPartition(namespace, tableName, internalPartitionValue, columnPartitionValue)
// delete partition(s) as indicated by the options argument (see Options Builder below)
IntradayControlImpl.deleteIntradayPartition(options)
Tip
You will want to check the results of these commands.
result = IntradayControlImpl.truncateIntradayPartition(...)
println result
println IntradayControlImpl.truncateIntradayPartition(...)
Options Builder
The options builder can be useful when programmatically constructing complex truncate
or delete
commands.
import io.deephaven.configuration.IntradayControlImpl.Options
import io.deephaven.configuration.IntradayControlImpl
builder = Options.builder()
Modify the builder with the desired options, much like the dhctl
command line options.
Set the partition to be deleted:
builder.key("namespace", "tableName", "columnPartition")
builder.key("namespace", "tableName", "internalPartition", "columnPartition")
builder.key(key)
For example:
key = new FullTableLocationKey.AggregateTableLocationKey("DbInternal", "ProcessEventLog", SYSTEM_INTRADAY, lastBusinessDateNy())
builder.key(key)
builder.key("DbInternal", "ProcessEventLog", lastBusinessDateNy())
Note
Only one key is permitted at this time. You can call one of the key()
methods again, but you must call builder.clearKey()
in between.
Dry run options
Change the dry run option:
builder.dryRun() // delegates to builder.dryRun(true)
builder.dryRun(true) // perform a dry run, and do not perform the truncate or delete action
Authentication
Change the authentication (by default, the command will be run using the default authentication of the worker):
builder.authenticate("username", "password")
builder.authenticate("username", "password", "operateAsUser")
builder.authenticate("path_to_keyfile") // keyfile must be readable by the worker
builder.authenticate() // do default authentication, according to process environment and properties
Add a DIS
Add a DIS to the include
or exclude
list:
builder.include("dis_name")
builder.exclude("dis_name")
Build options
Build the options as configured in the builder. You may call build()
multiple times. This allows you to use a builder to check a dry run and then perform the delete, or to change the key in a loop.
opts = builder.build()
You can invoke the truncate
or delete
methods directly from the builder or options:
result = builder.doTruncate()
result = opts.doTruncate()
println result
result = builder.doDelete()
result = opts.doDelete()
println result
You can pass the options to the Intraday Control tool and check the results:
result = IntradayControlImpl.truncateIntradayPartition(opts)
println result
You can display the contents of the builder or options:
println builder
println opts
Check the results
Truncate and delete commands return result objects containing detailed information about the operation. The intraday operations can be complex, so the result object is also necessarily complex.
The DISCommandUtil.ActionResult
object has an overall result that indicates success or failure of the operation as a whole.
It also contains a map of results for each DIS that was involved in the operation.
There is an overall result code for each DIS, and a collection of results for the individual locations that were processed.
The code examples below illustrate how to check the results at various levels of detail. These are intended as examples; adjust the code to suit your needs.
This example executes a truncate
dry run, and then executes the truncate
only if none of the locations to be truncated are still in use:
import io.deephaven.configuration.IntradayControlImpl
import com.illumon.iris.db.tables.dataimport.logtailer.DISCommandUtil
namespace="DbInternal"
tableName="ProcessEventLog"
date=currentDateNy()
def builder = IntradayControlImpl.Options.builder()
.key(namespace, tableName, date)
.dryRun(true)
dryRunResult = builder.doTruncate()
// verify the overall result
okToTruncate = dryRunResult.getSummaryResult() == DISCommandUtil.ActionResult.Result.SUCCESS
// verify all the if any DIS results are success
okToTruncate = okToTruncate &&
dryRunResult.getDisResultsMap().values().every { disResult -> disResult.getResult() == DISCommandUtil.ActionResult.Result.SUCCESS }
// check for locations being actively tailed
hasActiveProcessor = dryRunResult.getDisResultsMap().values().any { disResult -> disResult.getLocationResults().any { locationResult -> locationResult.hasActiveProcessor() } }
okToTruncate = okToTruncate && !hasActiveProcessor
println okToTruncate
if (okToTruncate) {
builder.dryRun(false)
commandResult = builder.doTruncate()
println commandResult
}
This example executes a truncate
command and then, if the truncate was successful, delete
:
import io.deephaven.configuration.IntradayControlImpl
import com.illumon.iris.db.tables.dataimport.logtailer.DISCommandUtil
namespace="DbInternal"
tableName="ProcessEventLog"
date="2025-03-19"
truncateResult = IntradayControlImpl.truncateIntradayPartition(namespace, tableName, date)
printf "Truncate %s.%s partition %s: \n", namespace, tableName, date
println truncateResult
// verify the overall result
if (truncateResult.getSummaryResult() == DISCommandUtil.ActionResult.Result.SUCCESS &&
truncateResult.getDisResultsMap().size() >= 1 &&
truncateResult.getDisResultsMap().values().every { disResult -> disResult.getResult() == DISCommandUtil.ActionResult.Result.SUCCESS }) {
deleteResult = IntradayControlImpl.truncateIntradayPartition(namespace, tableName, date)
printf "Delete %s.%s partition %s: \n", namespace, tableName, date
println deleteResult
}
Rescan tables
This command instructs the DIS handling table DbInternal.ProcessEventLog
to look for new data:
import io.deephaven.configuration.IntradayControlImpl
result = IntradayControlImpl.rescanTable("DbInternal", "ProcessEventLog")
println result
...
Re-scan Result: SUCCESS
DIS: db_dis(all)
Result: SUCCESS
This command instructs all DISs to look for new data for all tables:
import io.deephaven.configuration.IntradayControlImpl
result = IntradayControlImpl.rescanAll()
println result
...
Re-scan Result: SUCCESS
DIS: db_dis(all)
Result: SUCCESS
DIS: Ingester1(all)
Result: SUCCESS
Caveats
- This method makes a best-effort attempt to delete everything on all appropriate Data Import Servers. This cannot be atomic, so the operation might have only partial success. Make sure you check all the results.
- The truncated partitions are marked as permanently truncated, and further ingestion of data will be disallowed. This is to prevent confusion if loggers produce new data for the partition, or if tailers have not finished all existing data files.
- Before logging new data for the truncated partitions, remove any existing data files (bin files), and then delete the partitions with
dhctl intraday delete ...
. - It is possible to delete data on one Data Import Server and leave it on another (e.g., a backup). Be extremely careful with this, as it can create confusion.