← Back to team overview

drizzle-discuss team mailing list archive

Re: Improving the Engine API


Hi Jay,

On Dec 8, 2009, at 5:23 PM, Jay Pipes wrote:

Whatcha say? :)
Absolutely, it will work. And maybe it is the best solution.
I would have suggested that Drizzle assumes that DDL works with transactions, and that the engine handles the situation by doing one of the following:
- Execute the DDL normally, because it supports DDL in transactions,
- Return an error because it does not handle DLL in a transaction, or
- Silently commit the transaction, and begin it again at the end of the DML statement, without Drizzle even knowing about it. But, I guess the problem is replication. If Drizzle is not aware of a transaction end, then it would be replicated as such, and we may end up with a different result on the slave. The problem of DDL in a transaction only occurs when auto-commit is disabled, or an explicit BEGIN is used, so lets look at a quick example:
INSERT t1 VALUES (1, 1);
INSERT t1 VALUES (2, 2);
INSERT t1 VALUES (3, 3, 3);
INSERT t1 VALUES (4, 4, 4);
A silent COMMIT on DML will lead to the following:
INSERT t1 VALUES (1, 1);
INSERT t1 VALUES (2, 2);
INSERT t1 VALUES (3, 3, 3);
INSERT t1 VALUES (4, 4, 4);
While I am no fan of a silent COMMIT, it may be the best solution, because at least this sequence of statements will be compatible with engines that support DDL in transactions and those that don't (much like MyISAM happily ignores BEGIN TRANSACTION). The alternative would be to return an error. This would prevent the surprise affect that I get when the server crashes and I discover my transaction was not atomic after all.

Well, I'm not a huge fan of implicit anything, as you know, but in this case, since engines do have a certain leeway in how they advise the kernel that they will handle a statement, I'm OK with continuing the existing MySQL behaviour of implicitly committing transactions before DDL statements are executed -- but in Drizzle's case, only if the engine advises it is unable to include the DDL in the current transaction.

Yup, I can live with that too...

I guess this is a question for the DBA's on the list ... input please! :)


Last chance to object... :)

Also, one other thing we need to discuss is the following, which you alluded to in an earlier email:

Suppose PBXT can handle ADD INDEX in an optimized fashion, but PBXT does not implement the remainder of the ALTER TABLE statement and prefers Drizzle's kernel to handle the other operations. In this particular case, we need a way of allowing the engine to communicate that it would like to handle *some part* of a statement internally, and let the kernel handle other parts. This is an interesting problem, and I can see at least three possible solutions. Let me know what you think of either of these:

1) Establish two more flags for the StatementExecutionIntent:


In the first flag, the engine is telling the kernel that it wishes to execute some part of the Statement *after* the kernel has finished executing the statement. In the second flag, the engine is telling the kernel it wants first crack at the statement.

I can see this solution being of medium-difficulty to implement, as lots of edge cases would have to be tested...

2) Don't add new flags to StatementExecutionIntent, but instead have the engine "do its thing" (e.g. optimizally implement the ADD INDEX part of an ALTER TABLE) in the call to StorageEngine::endStatement().

3) Create a new plugin type: plugin::PostKernelStatementExecute:

namespace drizzled {
namespace plugin {

* Modules implement a subclass of this class and register
* an instance of the class as a "listener" for when the
* kernel has completed execution of a Statement.
* For example, a storage engine might implement a subclass
* called OptimizedAddIndex which would listen for the kernel's
* completed execution of an ALTER TABLE statement and execute
* an optimal ADD INDEX clause for the ALTER TABLE statement.
class PostKernelStatementExecute
 bool operator()
   (Session &session, const message::Statement &statement);

Have the engine register a PostKernelStatementExecute trigger/hook. This PostKernelStatementExecute would be a subclass of the above plugin interface class and would allow the engine to react to certain types of statements that it asks the kernel to execute "normally" but wants to add some optimized path for...


I like (2) above, because it is simple. I see 2 variations:

A) As per (2) above, let the engine do the extra stuff in startStatement() and/or endStatement().

B) Add the following call sequence:

.... standard execution of the statement

Unless there is a reason why (A) or (B) will not work, then I think it is better than adding additional flags or method registration to the API.

Everyone knows how to override a method, so the documentation for preStatement(), for example, is simple:

This method is called after startStatement() and before the standard execution of the statement. Override it if you need to do something at this point.

Paul McCullagh
PrimeBase Technologies

Follow ups