From: Adriano d. S. F. <adr...@gm...> - 2011-03-23 14:29:16
|
On 23-03-2011 09:42, Alex Peshkoff wrote: > >> so look at PProvider methods and >> forget about transactions for now (it's the same concepts). The yvalve >> calls the provider passing the address of an IAttachment* and a handle >> just allocated. >> >> Once the engine setups an attachment, it puts it address in *ptr. This >> is the place which the yvalve uses, so even before attachDatabase >> returns, the yvalve can be called and access the database. >> >> This is not good solution, and now exposes internal ugliness to the API. >> The "api" parameters means nothing for user code, and a returned >> IAttachment is clean than an IAttachment** parameter. > > In private discussion Dmitry Kovalenko told me the contrary :-) > But personally I agree - API in which new objects are returned, not > Object** parameter is passed, looks better. > >> And this don't solve the problem with autonomous transactions, created >> inside the engine and used by external engines. To support this, we need >> new approach. It's the engine who needs to ask the yvalve to register an >> object and get its handle (yvalve object). >> >> But this must not be done directly, since providers could be chained to >> implement things (say trace provider > > we discussed it and decided it's bad idea > You can decide it for Firebird, but you can't decide it for user. Let user create *plugins*. >> , log/replay provider > > which must log only external calls > Code from external engines *is* external calls. May not make sense for a replay plugin, but it must pass in the yvalve too. > > I think that for current attachment (and transaction) external engines > must directly use appropriate engine interfaces. > Same for transactions created internally. > No, please. Let create good and unified thing, not a lot of specific thing because we don't want to think. >> I propose IProviderManagement interface. The yvalve will creates an >> instance of IProviderManager and will pass it to the factory that >> creates a provider. So when an provider is created, it receives an >> yvalve IProviderManagement (or something else that indirectly calls the >> yvalve object). >> >> It will have these kind of methods: >> - virtual IAttachment* registerAttachment(IAttachment* attachment) = 0; >> - virtual void freeAttachment(IAttachment* attachment) = 0; >> >> registerAttachment receives the engine object and creates and returns an >> yvalve object. Remember, ProviderManager instance was created by yvalve. >> freeAttachment receives the yvalve object and makes the yvalve object >> orphan, that is, all calls on it will not call the engine provider >> anymore but will return an error. >> >> Now how this is going to be used. Say we have: >> >> ------------ >> IAttachment* JrdProvider::attachDatabase(...) >> { >> JrdAttachment* attachment = new ...; >> ... >> >> attachment->external = providerManager->registerAttachment(attachment); >> >> ... >> // database triggers will call external code passing an >> attachment->external >> runDatabaseTriggers(attachment); >> >> return attachment; >> } >> >> Attachment::~Attachment() >> { >> providerManager->freeAttachment(this->external); >> } >> ------------ >> >> Then we solve three problems: >> 1) API ugliness: unused (by user code) parameters and refcount >> 2) External access to objects created internally >> 3) Management of freed objects >> >> Actually, we can solve another problem. Note the IStatement method >> below. The problem is that a dsql_req (IStatement) cannot be reprepared >> internally, so a new object must be created. >> >> // FixMe - prepare must return void, not new statement handle >> virtual IStatement* FB_CARG prepare(Status* status, ITransaction* tra, >> unsigned int stmtLength, const char* sqlStmt, unsigned int dialect, >> unsigned int itemLength, const unsigned char* items, >> unsigned int bufferLength, unsigned char* buffer) = 0; >> >> We can do something like: >> >> dsql_req::prepare(...) >> { >> dsql_req* newStatement = ...; >> providerManager->replaceStatement(this->external, newStatement); >> } >> > > Adriano, are you serious that all described here is simpler than proxy > objects in engine? :-) > I'm *sure* it is. I showed you ~15 lines of code, against addRefs/releases around by Firebird and all-over-the-world users code. And, BTW, it will not crash when the engine is unloaded, like I said in the another message. Adriano |