You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@couchdb.apache.org by Antony Blakey <an...@gmail.com> on 2009/02/02 06:40:56 UTC

Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

I've recreated my simple erlang plugins system

   http://github.com/AntonyBlakey/couchdb/tree/simple-erlang-plugins

A plugin is a directory. It can contain a plugin.ini file and an  
erlang directory.

The erlang directory is added to the erlang load path - you put your  
beam files in there.

The plugin.ini file is loaded after the default.ini, but before  
local.ini. If you supply your own ini files on the command line then  
it comes before them.

To start your plugin you probably want to add to the [daemons] section  
of your plugin.ini file. Check start_secondary_services in  
couch_server_sup.erl to see what happens with daemons, and you can see  
examples in default.ini (.tpl.in in the source).

If plugins need to be integrated in a different fashion, or  
dependencies are needed, then I'd suggest that a different config  
section be created to handle richer specification/invocation option  
format than [daemons].

There are command line options for manipulating the list of plugins.  
By default it will load plugins from /etc/couchdb/plugins/ or whatever  
your localconfdir is - mine is always relative - but this can be  
controlled by the options:
   -C      clean the plugins list
   -D      add all the plugins in $DEFAULT_PLUGIN_DIR
   -G DIR  add all the plugins in DIR
   -P DIR  add the plugin DIR
Bit light on testing, I wanted to show how trivial it is.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

There are two ways of constructing a software design: One way is to  
make it so simple that there are obviously no deficiencies, and the  
other way is to make it so complicated that there are no obvious  
deficiencies.
   -- C. A. R. Hoare



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 8:56 PM, Noah Slater wrote:

> I've found this thread a little hard to follow so far, but why not  
> configure the
> plugins from /etc/couchdb/local.ini itself, including the  
> configuration that
> tells CouchDB which plugins to work. I'm not sure I'm comfortable  
> with the idea
> of CouchDB scanning a list of directories each time, loading things  
> automatically.

I did it this way to avoid touching the CouchDB code, and not wanting  
to impose another file format or do parsing in shell script.  
Especially given that I have an imminent requirement for CouchDB/Win32  
where the shell is complete shit. OTOH I may have to replace the start  
script with C for that reason.

It might be better to have an erlang plugin manager that can deal with  
plugin selection, dependencies and ordering requirements, but that's a  
more intrusive solution.

Antony Blakey
--------------------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

The greatest challenge to any thinker is stating the problem in a way  
that will allow a solution
   -- Bertrand Russell


Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Noah Slater <ns...@apache.org>.
On Mon, Feb 02, 2009 at 06:07:37PM +1030, Antony Blakey wrote:
> My concern is how to allow plugins to be updated without stomping on
> user configuration, which is why I suggest having the local plugin
> configuration be outside of the plugin's directory. Maybe that's a
> deployment required that's unlike to happen, but I look forward to a
> time when couch plugins are like rubygems and regular updating is
> common.

I've found this thread a little hard to follow so far, but why not configure the
plugins from /etc/couchdb/local.ini itself, including the configuration that
tells CouchDB which plugins to work. I'm not sure I'm comfortable with the idea
of CouchDB scanning a list of directories each time, loading things automatically.

-- 
Noah Slater, http://tumbolia.org/nslater

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 5:36 PM, Chris Anderson wrote:

> Maybe each plugin could have a default.ini and a local.ini, so  
> something like:
>
> plugins/
>    geo_index/
>        Makefile.am.in
>        src/
>            geo_index.erl
>            geo_httpd.erl
>            geo_manager.erl
>        default.ini
>        local.ini
>    ...
>
>
> Then CouchDB could automatically pickup plugin config from each
> directory, running all the defaults before all the locals.

I think we may be talking at cross-purposes here - I'm thinking  
particularly of plugins that are separately compiled without being  
included in the canonical sources, while I gather you're focussed on a  
refactored core or a way to handle less tightly coupled contributions.  
I'm interested in seeing those things happen, but I'll be guided by  
you as to what I should for that. In particular I know sfa about  
automake et al.

OTOH, I think top level default.ini + local.ini + local.*.ini would be  
a good idea regardless, and a simple change.

> I'm not invested in these specifics, just trying to think of ways it
> could look that would give new developers the least amount of
> head-scratching.

I think head-scratching would be best mitigated by some good docs. If  
we want to implement this then I'll commit to writing a spec/tutorial  
on the wiki.

My concern is how to allow plugins to be updated without stomping on  
user configuration, which is why I suggest having the local plugin  
configuration be outside of the plugin's directory. Maybe that's a  
deployment required that's unlike to happen, but I look forward to a  
time when couch plugins are like rubygems and regular updating is  
common.

Somewhat OT: plugins are also a mechanism for deploying generic non- 
couch functionality for a deployment scenario like mine where every  
user runs a Couch instance ala Notes client e.g. distributed voting  
algorithms and scalaris-like functionality for emergent clusters  
within wider p2p meshes.

Antony Blakey
--------------------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

Plurality is not to be assumed without necessity
   -- William of Ockham (ca. 1285-1349)



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Chris Anderson <jc...@apache.org>.
On Sun, Feb 1, 2009 at 10:39 PM, Antony Blakey <an...@gmail.com> wrote:
>
> I imagined that the ini file in the plugin directory wouldn't be modified by
> users i.e. that's "part of the plugin". Users would modify the local.ini
> file to change the user-configurable parts of that. That makes me think that
> the startup script should load local.*.ini, so you can separate your
> per-plugin user-configurable bits. The reason for not modifying the
> plugin.ini directly is so that you can update them easily.
>

There's a bunch of ways we could do this. The simplest overall system
I can think of would be a `make plugins` target that builds whatever
is in the plugins directory.

Maybe each plugin could have a default.ini and a local.ini, so something like:

plugins/
    geo_index/
        Makefile.am.in
        src/
            geo_index.erl
            geo_httpd.erl
            geo_manager.erl
        default.ini
        local.ini
    ...


Then CouchDB could automatically pickup plugin config from each
directory, running all the defaults before all the locals.

I'm not invested in these specifics, just trying to think of ways it
could look that would give new developers the least amount of
head-scratching.

-- 
Chris Anderson
http://jchris.mfdz.com

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 4:46 PM, Chris Anderson wrote:

> On Sun, Feb 1, 2009 at 9:40 PM, Antony Blakey  
> <an...@gmail.com> wrote:
>> There are command line options for manipulating the list of  
>> plugins. By
>> default it will load plugins from /etc/couchdb/plugins/ or whatever  
>> your
>> localconfdir is - mine is always relative - but this can be  
>> controlled by
>> the options:
>
>> -C      clean the plugins list
>> -D      add all the plugins in $DEFAULT_PLUGIN_DIR
>> -G DIR  add all the plugins in DIR
>> -P DIR  add the plugin DIR
>> Bit light on testing, I wanted to show how trivial it is.
>
> Thanks for getting started on this. It looks like with a make plugins
> target, this will be ready to roll.

I think there are multiple levels of modularity possible - some core  
features could be plugins, purely in a separation-of-concerns kind of  
way. Then there would be third-party plugins. This could be a  
convenient way to play with some new contributions without having to  
merge into the a single code directory (assuming each plugin is  
separate in the source). And finally there would be per-user plugins  
that customize couch on a per-app basis.

I assume you mean a make plugins target for core plugins?

> One thing I don't understand is the plugins list and the additional
> command-line options to launch script. I wonder if there's a
> non-ephemeral way to control the list of loaded plugins.

Well, there is the default location. If a plugin were to have an  
extension e.g. '.plugin' then the activation could be controlled via  
renaming. OTOH I like the Apache (httpd) mechanism of having  
'available/active' dirs, which seems cleaner.

I use the command line options to the startup script because I have  
couchdb/erlang/icu etc packaged as ruby gems that deploys couch using  
dependcies, and the class that controls couchdb allows multiple  
instances in self-contained locations. It looks a bit like this:

---------------------------------------

require 'memetic'
require 'memetic-erlang'
require 'memetic-spidermonkey'
require 'memetic-icu'

module Memetic

   class CouchDB

     DIRECTORY = %x{cd #{File.dirname(File.dirname(__FILE__)) + "/ 
BUILD"} ; pwd}.split()[0]

     def CouchDB.configure_environment(env)
       Erlang.configure_environment(env)
       Spidermonkey.configure_environment(env)
       ICU.configure_environment(env)
     end

     def initialize(local_directory)
       @local_directory = local_directory
       Dir.mkdir(@local_directory) unless File.exists?(@local_directory)

       @log_directory = "#{@local_directory}/log"
       Dir.mkdir(@log_directory) unless File.exists?(@log_directory)

       @data_directory = "#{@local_directory}/data"
       Dir.mkdir(@data_directory) unless File.exists?(@data_directory)

       File.open("#{@local_directory}/configuration.ini", "w") do |f|
         f << configuration()
       end

     end

     def start
       env = Environment.new
       CouchDB.configure_environment(env)
       cmd = env.as_command_prefix
       cmd << "( cd '#{DIRECTORY}' ; "
       cmd << "./bin/couchdb -b "
       cmd << "-o '#{@log_directory}/couchdb.stdout' "
       cmd << "-e '#{@log_directory}/couchdb.stderr' "
       cmd << "-p '#{@local_directory}/pid' "
       cmd << "-c './etc/couchdb/default.ini' "
       cmd << "-c '#{@local_directory}/configuration.ini' "
       #cmd << "-G '#{@local_directory}/plugins' "
       cmd << " )"
       IO.popen(cmd) do |p|
         s = p.gets
         s.chomp if s
       end
     end

     def status
       env = Environment.new
       CouchDB.configure_environment(env)
       IO.popen("#{env.as_command_prefix} #{DIRECTORY}/bin/couchdb -p  
#{@local_directory}/pid -s") do |p|
         s = p.gets
         s.chomp if s
       end
     end

     def stop
       env = Environment.new
       CouchDB.configure_environment(env)
       IO.popen("#{env.as_command_prefix} #{DIRECTORY}/bin/couchdb -p  
#{@local_directory}/pid -d") do |p|
         s = p.gets
         s.chomp if s
       end
     end

     def configuration
       return <<END_OF_STRING
[couchdb]
database_dir = #{@data_directory}

[log]
file = #{@log_directory}/couch.log
level = debug
END_OF_STRING
     end

   end

end

---------------------------------------

> As far as configuration, users will likely also want to configure
> their API endpoints as http_db_handlers or http_global_handlers. These
> allow you to hook an Erlang function directly to a CouchDB path.

Sure.

I imagined that the ini file in the plugin directory wouldn't be  
modified by users i.e. that's "part of the plugin". Users would modify  
the local.ini file to change the user-configurable parts of that. That  
makes me think that the startup script should load local.*.ini, so you  
can separate your per-plugin user-configurable bits. The reason for  
not modifying the plugin.ini directly is so that you can update them  
easily.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

A reasonable man adapts himself to suit his environment. An  
unreasonable man persists in attempting to adapt his environment to  
suit himself. Therefore, all progress depends on the unreasonable man.
   -- George Bernard Shaw



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Chris Anderson <jc...@apache.org>.
On Sun, Feb 1, 2009 at 9:40 PM, Antony Blakey <an...@gmail.com> wrote:
> There are command line options for manipulating the list of plugins. By
> default it will load plugins from /etc/couchdb/plugins/ or whatever your
> localconfdir is - mine is always relative - but this can be controlled by
> the options:

>  -C      clean the plugins list
>  -D      add all the plugins in $DEFAULT_PLUGIN_DIR
>  -G DIR  add all the plugins in DIR
>  -P DIR  add the plugin DIR
> Bit light on testing, I wanted to show how trivial it is.

Thanks for getting started on this. It looks like with a make plugins
target, this will be ready to roll.

One thing I don't understand is the plugins list and the additional
command-line options to launch script. I wonder if there's a
non-ephemeral way to control the list of loaded plugins.

At this point `utils/run` is still a copy-paste job from `couchdb`.
Now might be a good opportunity to make that more sensible.

As far as configuration, users will likely also want to configure
their API endpoints as http_db_handlers or http_global_handlers. These
allow you to hook an Erlang function directly to a CouchDB path.

-- 
Chris Anderson
http://jchris.mfdz.com

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Ben Browning <be...@gmail.com>.
To spark some additional conversation around plugins, is there a clear
idea how we would handle plugin X that also uses plugin Y? For
example, I could see the Erlang API, the partitioning/clustering
functionality, and individual pieces of the clustering as additional
plugins (consistent hashing algorithm being the immediately obvious
one). The partitioning would depend on the Erlang API and a consistent
hashing plugin being configured.

For now I'm just throwing additional modules in the src/couchdb
directory in my git branch but there are enough modules in there it
makes me hesitate to add more. We could separate these into multiple
folders by using Erlang packages, but a plugin system could accomplish
the same goal and provide additional benefit for 3rd-party plugins.

It's not a pressing priority, but getting a plugin system in-place
would better allow for 3rd-party development around CouchDB and make
it easier to release and version functionality separately from the
core app.


Ben

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Chris Anderson <jc...@apache.org>.
On Mon, Feb 2, 2009 at 4:39 AM, Antony Blakey <an...@gmail.com> wrote:
>
> On 02/02/2009, at 10:34 PM, Jan Lehnardt wrote:
>
>>
>> On 2 Feb 2009, at 12:45, Antony Blakey wrote:
>>
>>>
>>> On 02/02/2009, at 10:09 PM, Noah Slater wrote:
>>>
>>>> That's fine with me. (Says the man who's not going to develop it.)
>>>
>>> Unfortunately requiring a bigger commitment to this feature than I can
>>> manage at this time.
>>
>> I hope you can push for an agreed-upon design and give a rough todo list
>> and maybe start with it and leave open work items with a good description
>> in JIRA for others to pick up. Would that work?
>
> It's just a matter of doing in erlang what I did in the script, finding out
> how to extend the load path. Hopefully my implementation shows how
> conceptually trivial it is. I agree with Noah about the configuration issue.
> Probably the only trick is that you need to load the config to find the
> plugins and then load more config from each plugin.
>
> I need to focus on the transactional _bulk_docs issue, and then the filename
> patch - that's a 0.9 blocker.
>

Yes, I think having this thread open which lays out the possibilities
is good work as long as we can avoid losing them to history by the
time we are ready to implement the plugin thing.

I think dropping a patch in Jira with a someday/maybe priority is th
best way to let us pick back up when the time comes.



-- 
Chris Anderson
http://jchris.mfdz.com

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Jan Lehnardt <ja...@apache.org>.
On 2 Feb 2009, at 13:39, Antony Blakey wrote:

>
> On 02/02/2009, at 10:34 PM, Jan Lehnardt wrote:
>
>> I hope you can push for an agreed-upon design and give a rough todo  
>> list
>> and maybe start with it and leave open work items with a good  
>> description
>> in JIRA for others to pick up. Would that work?
>
> It's just a matter of doing in erlang what I did in the script,  
> finding out how to extend the load path. Hopefully my implementation  
> shows how conceptually trivial it is. I agree with Noah about the  
> configuration issue. Probably the only trick is that you need to  
> load the config to find the plugins and then load more config from  
> each plugin.
>
> I need to focus on the transactional _bulk_docs issue, and then the  
> filename patch - that's a 0.9 blocker.

Great, thanks. Focus is good.

Cheers
Jan
--

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 10:34 PM, Jan Lehnardt wrote:

>
> On 2 Feb 2009, at 12:45, Antony Blakey wrote:
>
>>
>> On 02/02/2009, at 10:09 PM, Noah Slater wrote:
>>
>>> That's fine with me. (Says the man who's not going to develop it.)
>>
>> Unfortunately requiring a bigger commitment to this feature than I  
>> can manage at this time.
>
> I hope you can push for an agreed-upon design and give a rough todo  
> list
> and maybe start with it and leave open work items with a good  
> description
> in JIRA for others to pick up. Would that work?

It's just a matter of doing in erlang what I did in the script,  
finding out how to extend the load path. Hopefully my implementation  
shows how conceptually trivial it is. I agree with Noah about the  
configuration issue. Probably the only trick is that you need to load  
the config to find the plugins and then load more config from each  
plugin.

I need to focus on the transactional _bulk_docs issue, and then the  
filename patch - that's a 0.9 blocker.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

The intuitive mind is a sacred gift and the rational mind is a  
faithful servant. We have created a society that honours the servant  
and has forgotten the gift.
   -- Albert Einstein



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Jan Lehnardt <ja...@apache.org>.
On 2 Feb 2009, at 12:45, Antony Blakey wrote:

>
> On 02/02/2009, at 10:09 PM, Noah Slater wrote:
>
>> That's fine with me. (Says the man who's not going to develop it.)
>
> Unfortunately requiring a bigger commitment to this feature than I  
> can manage at this time.

I hope you can push for an agreed-upon design and give a rough todo list
and maybe start with it and leave open work items with a good  
description
in JIRA for others to pick up. Would that work?

Cheers
Jan
--

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 10:09 PM, Noah Slater wrote:

> That's fine with me. (Says the man who's not going to develop it.)

Unfortunately requiring a bigger commitment to this feature than I can  
manage at this time.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

A Buddhist walks up to a hot-dog stand and says, "Make me one with  
everything". He then pays the vendor and asks for change. The vendor  
says, "Change comes from within".




Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Noah Slater <ns...@apache.org>.
On Mon, Feb 02, 2009 at 10:06:48PM +1030, Antony Blakey wrote:
>
> On 02/02/2009, at 9:48 PM, Noah Slater wrote:
>
>> I think I agree with a comment earlier in this thread. I don't think
>> command
>> options are the place for this type of configuration. Ideally, you'd
>> want all
>> the configuration in the ini file.
>
> That means that the plugin system needs to be written in CouchDB itself,
> rather than being a lightweight launch-time facility.

That's fine with me. (Says the man who's not going to develop it.)

-- 
Noah Slater, http://tumbolia.org/nslater

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 9:48 PM, Noah Slater wrote:

> I think I agree with a comment earlier in this thread. I don't think  
> command
> options are the place for this type of configuration. Ideally, you'd  
> want all
> the configuration in the ini file.

That means that the plugin system needs to be written in CouchDB  
itself, rather than being a lightweight launch-time facility.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

The ultimate measure of a man is not where he stands in moments of  
comfort and convenience, but where he stands at times of challenge and  
controversy.
   -- Martin Luther King



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Noah Slater <ns...@apache.org>.
On Mon, Feb 02, 2009 at 09:31:36PM +1030, Antony Blakey wrote:
>>>  -D      add all the plugins in $DEFAULT_PLUGIN_DIR
>>>  -G DIR  add all the plugins in DIR
>>>  -P DIR  add the plugin DIR
>>
>> Why have you chosen all capitals?
>
> Because all the obvious lower case options have been used. I wanted to
> use long options, but the shell getopts doesn't allow it.

I think I agree with a comment earlier in this thread. I don't think command
options are the place for this type of configuration. Ideally, you'd want all
the configuration in the ini file. If you really need to override some ini file
setting, maybe using an environment variable would be the way forward.

Bottom line: I want to keep the number of command line options small.

-- 
Noah Slater, http://tumbolia.org/nslater

Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Antony Blakey <an...@gmail.com>.
On 02/02/2009, at 8:51 PM, Noah Slater wrote:

> This sounds pretty good.
>
> On Mon, Feb 02, 2009 at 04:10:56PM +1030, Antony Blakey wrote:
>>  -C      clean the plugins list
>
> What does this do? I think it needs more explanation.

clear the plugin list.

The plugin list is by default all the plugins in $DEFAULT_PLUGIN_DIR. - 
C clears the list, either to run without plugins, or as a precursor to  
using -D -G -P in some order to define a specific plugin ordering and/ 
or load additional plugins from non-default locations.

>>  -D      add all the plugins in $DEFAULT_PLUGIN_DIR
>>  -G DIR  add all the plugins in DIR
>>  -P DIR  add the plugin DIR
>
> Why have you chosen all capitals?

Because all the obvious lower case options have been used. I wanted to  
use long options, but the shell getopts doesn't allow it.

Antony Blakey
-------------
CTO, Linkuistics Pty Ltd
Ph: 0438 840 787

There are two ways of constructing a software design: One way is to  
make it so simple that there are obviously no deficiencies, and the  
other way is to make it so complicated that there are no obvious  
deficiencies.
   -- C. A. R. Hoare



Re: Simple erlang plugins (was Re: couch_gen_btree: pluggable storage / tree engines)

Posted by Noah Slater <ns...@apache.org>.
This sounds pretty good.

On Mon, Feb 02, 2009 at 04:10:56PM +1030, Antony Blakey wrote:
>   -C      clean the plugins list

What does this do? I think it needs more explanation.

>   -D      add all the plugins in $DEFAULT_PLUGIN_DIR
>   -G DIR  add all the plugins in DIR
>   -P DIR  add the plugin DIR

Why have you chosen all capitals?

-- 
Noah Slater, http://tumbolia.org/nslater