From: Alex P. <pes...@ma...> - 2010-10-29 13:54:16
|
On 10/27/10 03:48, Adriano dos Santos Fernandes wrote: > On 26-10-2010 11:21, Alex Peshkoff wrote: > >> It's not a problem to convert text file to part of C++ program. But if >> it's not editable as resource, it makes no sense to do it. >> > This is not really very important. It's just internal design, there is > lot of more important things. > Definitely yes. > I'll just say one: > > - With multi-provider, how each provider (engines, client) are going to > be configured? I mean, by default located file and by API. Almost same (but in other form) problem was raised by Vlad privately. OK - let's try to finish with configuration. But before configuring plugins engine must know exactly how to identify them? Under what name does engine What means "name of plugin"? We have 4 candidates: - name of module, containing plugin (module name), - name of interface, i.e. type of plugin (interface name), - name, given by developer of plugin, in other words name of the implementation of given interface (implementation name), - something else. Module name is definitely bad - we may have modules, containing multiple plugins. Same for interface name - using multiple plugins of given type is our normal operation mode. Not long ago I was sure that implementation name is OK. But there is one problem. Imagine two independent companies, that both developed authentication plugins. Both called module GreatAuth and implementation name of plugin also GreatAuth (recommended practice is to make them match in case of single plugin per module). Some third company wants to use both. It's possible to rename dynamic library, but how will plugin manager later distinguish between 2 GreatAuth-s? Looks like we need to take into an account both module name and implementation name. Certainly, we may use when needed a form like 'ModuleName.ImplementationName', but on my mind it's better to give plugin in this case artificial _plugin name_ (like we do with UDFs), and use it later. Moreover, when defining it we must take into an account an ability to provide to plugin name of recommended(!) configuration file (plugin developers may ignore it, but this is not recommended for them to do). With all this said it becomes clear that some engine (not plugin) specific configuration is required. This is two-level configuration, like Plugin = PluginName { Module = ModuleName Implementation = ImplementationName ConfigFile = FileName } Please also notice, that it makes no sense to mention interface name here because type (i.e. interface name) of particular implementation may always be asked from master interface of plugin. Such entries might be added to firebird.conf, but this breaks historical format of that file, where each key must be entered single time. Therefore it's suggested to add file plugins.conf, which ensures how are plugins loaded, named and configured. Because we have nothing except plugins' description in it, a bit simpler format may be used: PluginName { Module = ModuleName Implementation = ImplementationName ConfigFile = FileName } Should notice, that in simple (and most often) case when for all names are same (i.e. PluginName == ModuleName == ImplementationName), no duplicates are present and configuration file name is derived from plugin name, this file is not needed at all. But it's presence helps us solve cases of any complexity. Not all plugins are always available. For example, in firebird.conf we may have Providers = remote, engine12 but in aliases.conf have a record for some specific database oldDb = path........... { provider = engine11 } Having such rather complex configuration let's describe how are plugins (more precise - modules with plugins) are loaded and what interfaces are used to talk to them. Plugins may be external or builtin. Builtin plugins are needed first of all to avoid dividing fbclient library into a lot of smaller parts. Somewhy community treats single-file-copy install as a feature:-) We should better support it. When some plugin is needed to firebird, plugin manager first of all checks - may be it's already here. If not - scans plugins.conf for description of desired plugin. If present, module name and implementation name are taken from this file (default for missing one - plugin name). If record for plugin with given name is missing, module name and implementation name are decided to be equal to plugin name. If module was not loaded yet, it is loaded. After it function (the only one visible externally), initializing module, is invoked. Parameter passed to it is system interface, using which plugins may interact with firebird. And first action performed by plugins - register in plugin manager, informing it about plugin type (same with interface name), implementation name and entrypoint for the future interaction. If that implementation name != module name and such pair is missing in plugins.conf, plugin manager skips plugin - it's anyway can not be used in any way. After module initialization plugin manager knows exactly, does it have requested implementation name in the module. If everything is OK, plugin manager passes configuration file name (dedault for it is something like $(fbroot)/plugins/$(plugin name).conf, but another value may be also specified in plugins.conf) to registered implementation's entrypoint - and at least get's plugin entrypoint, ready to produce instances of given plugin with given configuration passed, which may be called plugins' factory. Builtin plugins are registered during server startup. Builtin plugins are one that are linked in same module with our master library (fbclient) or client using, for example remote server. Client application (if desired) may also contain builtin plugins. Builtin plugins have 2 specifics. First is slightly different registration process - we should provide to plugin manager an entrypoint which will be called with system interface parameter. This operation is trivial when plugins are built into fbclient, but in case of remote server (or other client app) separate API call is required. [Another possible solution - we highly need builtin p,lugins in fbclient. May be avoid them in remote server (or client app) at all?] And module name does not make sense for builtin plugins - they are always registered under plugin name equal to implementation name. All the rest interface is absolutely same for both builtin and external plugins. Now a few words about how does plugin get configuration parameters. As was already mentioned, plugin implementation is notified about recommended filename at class factory creation step. Best practice for plugin programming (provided it needs any config at all) is to pass that name to system interface. As the result plugin gets config file interface, using which it can find keys and values from configuration file. And (at least) the answer to initial question is simple after all that said. Certainly, to make engine11 work with existing embedded library from 2.5, that library must be placed in separate FbRoot and have firebird.conf in it. Plugin engine11 (loading that library) can load it for example as $(CurrentFbroot)/../fb25/lib/fbembed. Certainly, if something other not given in it's configuration file (do not mix it with firebird.conf for fbembedded from 2.5). > And BTW, how can I create a database using a provider that is not the > first one to accept the database creation? For example, "engine13, > engine12" is defined in the config but I want to create database in > engine12. Unfortunately, this can be done using aliases. Unfortunately because it's bad solution to use old ODS when new one exists. BTW, even if we miss such ability this is not regression - current engine can't be instructed to create database with old ODS. |