Subject | Re: [Firebird-Architect] External Engines (and Plugins) |
---|---|
Author | Vlad Khorsun |
Post date | 2008-06-23T18:19:37Z |
>> I'd said what we have as ExternalEngine is a set of rules of how to write loadable library which thisCan you, please, quote standard or show paragraph numbers which is described
>> EE plugin is able to load, obtain entrypoints from library and execute its
>> functions passing parameters and returning results. Also plugin may provide some
>> kind of run-time support for user library. But i see no relation with language,
>> sorry.
>>
> But for the database (accordingly to the standard) there are languages.
> If you do things in other way (and don't have one to suggest) we're
> going to complicate things.
LANGUAGE ?
>>> For example, there is the C++ (engine) plugin. It implements the CPPWhy ? We have interface to report errors to the engine. Exceptions must never
>>> language. Users will not reimplement it, but write libraries that
>>> register routines in the C++ plugin.
>>>
>> It have nothing common with C++ language itself i guess. I can write user
>> library for this plugin in Delphi and it will work.
>>
> Maybe you can, but is not the design goals. You will need to deal with
> Delphi->C++ exceptions conversions, for example.
cross layers boundaries.
> In the end you willNo. I already have Delphi library written for original implementation so i know
> write a Delphi plugin embedded in the library modules mixing layers.
what i said here.
>> BTW, do you have Java-plugin implemented ? If yes, does it requires Jaybird (orHmm, i thought it was already integrated into Jaybird. As for Java-plugin code
>> another Java connectivity driver) support as original plugin did ?
>>
> Well, since original implementors doesn't showed the Java code :-),
(C++ bridge between EE API and Jaybird, used JNI) you may ask Evgeney or Roman
and i'm sure they give it to you.
Also, i know Carlos (former maintainer of .Net provider) also have .Net plugin
written.
> I had need to start things. And I started yesterday. I never wrote JNIRoman, can you comment on Jaybird part, please ?
> code before, but I'm already able to load JVM, pass control to Java for
> functions, and access others (not the "current" attachment/transaction)
> databases using Jaybird with very small changes. Things are very basic yet.
>
> Yes, it requires Jaybird and don't think we should do other thing. I
> started things on firebird2 tree but I'll move (offline for now) to
> client-java tree. Do things on firebird2 tree looks attractive due to
> C++ class library and build things direct. But it will anyway requires
> Jaybird, and it will requires some changes on it. Also not many things
> of our class library will be needed on the Java plugin.
>>>> Why FB_CALL is defined as __stdcall for WIN32 only ?I don't understand this as argument.
>>>>
>>> Native calling convention from Windows is STDCALL. Also, the default
>>> calling convention for C++ functions in MSVC is THISCALL, that is
>>> STDCALL. Certainly, we may define FB_CALL as CDECL, but since COM used
>>> STDCALL, I think we should use it.
>>>
>>> And finally, the ISC API uses it too.
>>>
>> I made all EE API interface methods stdcall to have ability to write plugins in
>> Delphi. IIRC, i described this decision here. I.e. it was done nor because of
>> ISC API used it nor because of Windows\COM\etc.
>>
>> I asked you not why "stdcall" but why "stdcall" is for Windows only ?
>>
> Because it's Windows-only native (from API POV) calling convention.
>>>> Why values within Values class enumerated starting from 1 but not zero ?As we defining our own API we free to do anything we wish. Any "language"
>>>>
>>>>
>>> Do you talk about "index" parameter? This is how almost all SQL
>>> libraries works. I prefer indexes starting from 0, but I give up on this.
>>>
>> Who was pushed on you so hard so you gave up ? :)
>>
> The world seems to like counters starting from 1. They are incorrect, we
> know. :-) But there are many people to convince.
plugin author are free to redefine rules for its own wrapper. I know few Delphi
components set and all of them used zero-based indexes and have no problems with
it (remember Delphi ? its Pascal for which zero-based arrays is not natural). I
really wonder why our C++ based API must have such not-natural behavior...
>> Reference counting allows to release library as soon as no more reference on itI talk about DLL's contained implementation of Plugin. And ability to update
>> stayed in metadata cache. Therefore it allows to reload library without restart
>> of Firebird and without of extra notifications.
>>
> If unload/reload is done, entrypoint will be called again. So I guess
> you're not talking about the Plugin object received by the library, but
> about internal implementation of PluginManager/ExtEngineManager.
such DLL's without stop of Firebird.
> Anyway, I don't think unload is good. For Java plugin, for example, itWe can introduce plugin attribute in config file to explicitly set rule that
> will cause unload/reload of JVM.
plugin module must [not]be unloaded when no reference to it left.
>>>>> Inside the plugin entry point (firebirdPlugin), the plugin may registerThis is auto-load plugin which will receive notification in its constructor and
>>>>> extra functionality that may be obtained by Firebird when required.
>>>>> Currently only External Engines may be registered through
>>>>> Plugin::setExternalEngineFactory.
>>>>>
>>>>>
>>>> How it can be extended in future for new kinds of plugins ? Adding new
>>>> Plugin::setXXXFactory ?
>>>>
>>> Yes. All API set are versioned so they can be extended and used
>>> appropriated. But not all plugins will register through factories. Some
>>> may need to call simple Plugin:::setXXX methods.
>>>
>> I thought Firebird obtained ExternalEngine (or Trace, or INTL, etc) instance
>> via corresponding factory only, am i wrong ?
>>
> For ExternaEngine and for future INTL plugin, yes. For Trace, I don't
> know exactly how it works. But imagine a plugin that wants to receive
> these events:
> - engineInitialized
> - engineShutingDown
>
> There is no factory for it. It should be:
> class EngineListener
> {
> virtual void engineInitialized() = 0;
> virtual void engineShutingDown() = 0;
> };
>
> void Plugin::setEngineListener(EngineListener*);
second notification in destructor or using new fb_shutdown_callback call.
>>>> It seems for me it is better to introduce enumeration ofIt seems we again lost understanding of each other. I offer following:
>>>> known plugin types and create only universal method to register all kinds of
>>>> factories, such as
>>>>
>>>> Plugin::registerFactory(PluginKind, PluginFactory).
>>>>
>>>>
>>> This will cause a plugin to extend a whole set of methods to just do one
>>> thing.
>>>
>> I don't understand, explain please.
>>
> class PluginFactoryImpl : public PluginFactory
> {
> virtual createExternalEngine...
> virtual createCharacterSet... // this is EE plugin, but need to
> override all PluginFactory
> };
>
> And if you want to extend PluginFactory for each PluginKind, it doesn't
> differ much from current design.
1. Change your ExternalEngineFactory interface by
class PluginFactory
{
public:
virtual Plugin* FB_CALL createPlugin(Error*, const char** args) = 0;
}
2. Rename your Plugin interface to PluginManager and change its
setExternalEngineFactory method by
class PluginManager
{
public:
...
enum PluginKind {pkExternalEngine, pkTrace, pkIntl, ...};
virtual void FB_CALL registerPluginFactory(PluginKind kind, PluginFactory*
factory) = 0;
}
3. Firebird have PluginManager implementation and passed it into
PluginEntryPoint function when plugin library is loaded.
4. Plugin library implemented PluginFactory interface for each kind of contained
plugin and passed instance of each factory into obtained at PluginEntryPoint
function PluginManager::registerPluginFactory method.
5. PluginManager have all necessary additional methods (or interfaces) which may
be used by any plugin.
>>>> Also it seems better to use word "Plugin" instead of "ExternalEngine" for pluginNot sure i understand above correctly but hope my example may shed some light
>>>> API :)
>>>>
>>>>
>>> I do not like "external engine" or ESP words from original
>>> implementations. :-) But Plugin is generic. We may have the TracePlugin,
>>> for example. I think "Language Plugin" is a more appropriate term.
>>>
>> It seems you mixed generic PluginAPI (used to enumerate, load\unload and
>> configure loadable plugin libraries) with concrete API, implemented by plugin
>> (ExternalEngine API, Trace API, etc). PluginAPI must be isolated from all other
>> APIs, isn't is ?
>>
> I mean, TracePluginApi.h. The only thing that Plugin knows about
> ExternalEngine is that ExternalEngine is a class and that it (Plugin)
> have a interface factory to create that class.
on this.
>>> Because some things is better encoded in the metadata, and for triggersYou already said your trigger will read destination parameters from some table
>>> there is no parameter. For example, see my REPLICATE trigger example.
>>> The database designer chooses the datasource, and the trigger will read
>>> properties of that datasource from a table.
>>>
>> So, you offer to declare as many REPLICATE triggers as destination datasources
>> and mark each of them by corresponding datasource name in <misc info> ? I don't
>> think its OK. Instead i would put all destinations names into separate table and
>> read this table in one REPLICATE trigger.
> It will have another table to be read. In some cases no table may be
> needed, just the info.
;) In my case it will be simple join. And it will be reads once, not per record
as in your case.
>> It saves at least trigger call overhead.You will call trigger N times for N destinations. I will call it one time.
>>
> I don't understand.
Consider Java trigger - it have noticable call overhead.
>>>> PPS Do you plan to introduce interface for user defined aggregates ?...
> So I think we must discuss in another thread all things needed for it.No objections :)
> External interface may be then created it.
Regards,
Vlad