Open apavlo opened 10 years ago
Note: Abusing the TransactionInitRequest
as I describe here may cause other problems. The other option is to create special queries that actually invoke procedures. I think this more of a hack, but it is a second option if this one doesn't work out.
The following is a proposal on how to add support to allow a stored procedure invoke another stored procedure at runtime. The basic setup is that there will be a parent distributed txn running at one partition that holds the locks for other partitions. Then instead of sending a query request to the remote partitions, we want to send a request to execute a "child" stored procedure at the remote partitions. We assume that each child stored procedures invocation will execute as a single-partition txn.
The basic mechanism that we're going to use to make this work is the
PartitionExecutor's
support for speculative txns, except that the child txns will not have a new txn id.VoltProcedure
API to allow a stored procedure to queue other stored procedures. This should mimic the theVoltClient
API where you just pass in a string with the name of the procedure that you want and an array of input parameters. You will then need to add avoltExecProcs()
method toVoltProcedure
that will block until all of the child txns return their results. I would make the assumption that the child txns are all going to return a singleVoltTable
, so therefore your newvoltExecProcs()
should return aVoltTable[]
.TransactionInitializer.calculateBasePartition()
to figure out where each request should go. You can use a bogusclient_handle
parameter; it's not used for anything important. You will then need to extend theTransactionInitRequest
message type in hstoreservice.proto to include a new parameter that specifies that you are sending a request for a nested txn.HStoreCoordinator
using aPartitionCountingCallback
. This will allow you to block the thread until all of the child txns return theirTransactionInitResponse
to the parent txn.TransactionInitRequest
with the child txn flag arrives at the remote partitions, it will get passed toTransactionInitHandler.remoteHandler()
. Note that this happens even if the remote partition is at the sameHStoreSite
as the parent txn's base partition. Since we are re-using the same txnId as the parent, you need to make sure that you don't hit the assert in that method that complains about getting an init request with an existing txnId. You also need to make sure that you don't invokeHStoreSite.transactionInit()
with the request, since that will cause the txn to get queued. You instead want to send it directly to the targetPartitionExecutor
usingqueueStartTransaction()
. But you will have to create a temporaryLocalTransaction
handle for this txn in order to stuff in the properProcedure
,ProcParameter
, andRpcCallback
for the child txn invocation. otherwise, if we use the parent txn'sAbstractTransaction
handle, it will have invocation information for the parent procedure.PartitionExecutor.run()
, we poll our work queue and look for something to do. When specexec is enabled, thePartitionExecutor
will be able to process new messages that are added to its work queue. But now the problem is that it's going to get a txn invocation request with the same id as the current dtxn at that partition. There may be a bunch of asserts that perform sanity checks as you execute. We will probably have to take care of them one-by-one. You should also mark the txn as speculative so that thePartitionExecutor
does not try to commit it immediately when it finishes.RpcCallback
to send back aTransactionInitResponse
to the parent txn. Packaging up the message and getting it back to right location will happen automatically when you invokeRpcCallback.run()