[Couchdb Wiki] Update of Views_for_SQL_Jockeys by JoanTouzet

2012-01-24 Thread Apache Wiki
Dear Wiki user,

You have subscribed to a wiki page or wiki category on Couchdb Wiki for 
change notification.

The Views_for_SQL_Jockeys page has been changed by JoanTouzet:
http://wiki.apache.org/couchdb/Views_for_SQL_Jockeys?action=diffrev1=4rev2=5

Comment:
Removing outdated incomplete content in favour of the superior reference

  Include(EditTheWiki)
  
- The latest version is maintained at 
http://books.couchdb.org/relax/reference/views-for-sql-jockeys
+ This page now resides 
athttp://books.couchdb.org/relax/reference/views-for-sql-jockeys instead.
  
- 
- = View Cookbook for SQL Jockeys =
- 
- This is a collection of some common SQL queries and how to get the same 
result in CouchDB. The key to remember here is that CouchDB does not work like 
an SQL database at all and that best practices from the SQL world do not 
translate well or at all to CouchDB. This cookbook assumes that you are 
familiar with the CouchDB basics like creating and updating databases and 
documents.
- 
- == Using Views (CREATE / ALTER TABLE) ==
- 
- Using views is a two step process. First you ''define'' a view, then you 
''query'' it. This is analogous to defining a table structure (with indexes) 
using `CREATE TABLE` or `ALTER TABLE` and querying it using an SQL query.
- 
- === Defining a View ===
- 
- Defining a view is done by creating a special document in a CouchDB database. 
The only actual speciality is the `_id` of the document: it starts with 
`_design/`, for example `_design/application`. Other than that, it is just a 
regular CouchDB document. To make sure CouchDB understands that you are 
defining a view, you need to prepare the contents of that design document in a 
special format. Here is an example:
- 
- {{{
- {
-   _id: _design/application,
-   _rev: 1-C1687D17,
-   views: {
- viewname: {
-   map: function(doc) { ... },
-   reduce: function(keys, values) { ... }
- }
-   }
- }
- }}}
- 
- We are defining a view `viewname`. The definition of the view consists of two 
functions. The ''map function'' and the ''reduce function''. Specifying a 
reduce function is optional. We'll look at the nature of the functions later. 
Note that `viewname` can be whatever you like; `users`, `by-name`, or `by date` 
are just some examples.
- 
- A single design document can also include multiple view definitions, each 
identified by a unique name:
- 
- {{{
- {
-   _id: _design/application,
-   _rev: 1-C1687D17,
-   views: {
- viewname: {
-   map: function(doc) { ... },
-   reduce: function(keys, values) { ... }
- },
- anotherview: {
-   map: function(doc) { ... },
-   reduce: function(keys, values) { ... }
- }
-   }
- }
- }}}
- 
- === Querying a View ===
- 
- The name of the design document and the name of the view are significant for 
querying the view. To query the view `viewname` you perform a HTTP `GET` 
request to the following URI:
- 
- {{{
- /database/_design/application/_view/viewname
- }}}
- 
- `database` is the name of the database you created your design document in. 
Next up is the design document name and then the view name prefixed with 
`_view/`. To query `anotherview` replace `viewname` in that URI with 
`anotherview`. If you want to query a view in a different design document 
adjust the design document name.
- 
- 
- === Map  Reduce Functions ===
- 
- Map/Reduce is a concept that solves problems by applying a two-step process; 
aptly named the ''map'' phase and the 'reduce' phase. The map phase looks at 
all documents in CouchDB separately one after the other and creates a ''map 
result''. The map result is an ordered list of key-value pairs. Both key and 
value can be specified by the user writing the map function. A map function may 
call the built-in `emit(key, value)` function 0 to N times per document, 
creating a row in the map result per invocation.
- 
- CouchDB is smart enough to only run a map function once for every document, 
even on subsequent queries on a view. Only changes to documents, or new 
documents need to be processed anew.
- 
-  Map Functions 
- 
- Map functions run in isolation for every document. They can't modify the 
document and they can't talk to the outside world; they can't have 
''side-effects''. This is required so CouchDB can guarantee correct results 
without having to recalculate a complete result when only one document gets 
changed.
- 
- The map result looks like this:
- 
- {{{
- {total_rows:3,offset:0,rows:[
-   {id:fc2636bf50556346f1ce46b4bc01fe30,key:Lena,value:5},
-   {id:1fb2449f9b9d4e466dbfa47ebe675063,key:Lisa,value:4},
-   {id:8ede09f6f6aeb35d948485624b28f149,key:Sarah,value:6}
- }
- }}}
- 
- It is a list of rows sorted by the value of `key`. The `id` is added 
automatically and refers back to the document that created this row. The 
`value` is the data you're looking for. For example purposes, it's the girl's 
age.
- 
- The map function that produces this result is:
- 
- {{{
- function(doc) {
-   if(doc.name  

[Couchdb Wiki] Trivial Update of Views_for_SQL_Jockeys by JoanTouzet

2012-01-24 Thread Apache Wiki
Dear Wiki user,

You have subscribed to a wiki page or wiki category on Couchdb Wiki for 
change notification.

The Views_for_SQL_Jockeys page has been changed by JoanTouzet:
http://wiki.apache.org/couchdb/Views_for_SQL_Jockeys?action=diffrev1=5rev2=6

  Include(EditTheWiki)
  
- This page now resides 
athttp://books.couchdb.org/relax/reference/views-for-sql-jockeys instead.
+ This page now resides at 
http://books.couchdb.org/relax/reference/views-for-sql-jockeys instead.
  


[Couchdb Wiki] Update of Using_Views by JoanTouzet

2012-01-24 Thread Apache Wiki
Dear Wiki user,

You have subscribed to a wiki page or wiki category on Couchdb Wiki for 
change notification.

The Using_Views page has been changed by JoanTouzet:
http://wiki.apache.org/couchdb/Using_Views?action=diffrev1=7rev2=8

Comment:
Updated link to guide which is more complete

   * [[Introduction_to_CouchDB_views|Introduction to CouchDB Views]] An 
introduction to views
   * [[HTTP_view_API|HTTP view API]] How to use Views
   * [[View_Snippets|View Snippets]] Look at how others solved particular 
problems using views.
-  * [[Views_for_SQL_Jockeys|Views for SQL Jockeys]] How to translate SQL 
knowledge to CouchDB views
+  * --([[Views_for_SQL_Jockeys|Views for SQL Jockeys]])-- 
[[http://guide.couchdb.org/draft/cookbook.html|View Cookbook for SQL Jockeys]] 
How to translate SQL knowledge to CouchDB views
   * [[Views_for_Lotus_Geeks|Views for Lotus Geeks]] How to translate Lotus 
Notes views to CouchDB views
   * [[EnableErlangViews|Enable Erlang Views]] How to enable the native Erlang 
view server (since CouchDB 0.10.0)
  


[Couchdb Wiki] Update of View_Snippets by JoanTouzet

2012-01-24 Thread Apache Wiki
Dear Wiki user,

You have subscribed to a wiki page or wiki category on Couchdb Wiki for 
change notification.

The View_Snippets page has been changed by JoanTouzet:
http://wiki.apache.org/couchdb/View_Snippets?action=diffrev1=45rev2=46

  = View Snippets =
  TableOfContents()
  
- This page collects code snippets to be used in your [[Views]]. They are 
mainly meant to help get your head around the map/reduce approach to accessing 
database content. 
+ This page collects code snippets to be used in your [[Views]]. They are 
mainly meant to help get your head around the map/reduce approach to accessing 
database content.
  
  '''Remember''': the Futon web client silently adds ''group=true'' to your 
views.
  
  == Common mistakes ==
- 
  When creating a reduce function, a re-reduce should behave in the same way as 
the regular reduce. The reason is that CouchDB doesn't necessarily call 
re-reduce on your map results.
  
  Think about it this way: If you have a bunch of values ''V1 V2 V3'' for key 
''K'', then you can get the combined result either by calling 
''reduce([K,K,K],[V1,V2,V3],0)'' or by re-reducing the individual results: 
''reduce(null,[R1,R2,R3],1)''. This depends on what your view results look like 
internally.
  
- 
  == Get docs with a particular user id ==
- 
  {{{#!highlight javascript
  // map
  function(doc) {
@@ -26, +23 @@

}
  }
  }}}
- 
  Then query with ''key=USER_ID'' to get all the rows that match that user.
  
- 
  == Get all documents which have an attachment ==
- 
  This lists only the documents which have an attachment.
  
  {{{#!highlight javascript
@@ -42, +36 @@

}
  }
  }}}
- 
  In SQL this would be something like {{{SELECT id FROM table WHERE attachment 
IS NOT NULL}}}.
  
- 
  == Count documents with and without an attachment ==
- 
  Call this with ''group=true'' or you only get the combined number of 
documents with and without attachments.
  
  {{{#!highlight javascript
@@ -57, +48 @@

  emit(with attachment, 1);
}
else {
- emit(without attachment, 1); 
+ emit(without attachment, 1);
}
  }
  }}}
- 
  {{{#!highlight javascript
  // reduce
  function(keys, values) {
 return sum(values);
  }
  }}}
- 
  Using curl you can call it like this:
  
  {{{
- curl -s -i -X POST -H 'Content-Type: application/json' 
+ curl -s -i -X POST -H 'Content-Type: application/json'
-   -d '{map: function(doc){if(doc._attachments) {emit(\with\,1);} else 
{emit(\without\,1);}}, 
+   -d '{map: function(doc){if(doc._attachments) {emit(\with\,1);} else 
{emit(\without\,1);}},
-   reduce: function(keys, values) {return sum(values);}}' 
+   reduce: function(keys, values) {return sum(values);}}'
'http://localhost:5984/somedb/_temp_view?group=true'
  }}}
- 
  In SQL this would be something along the lines of {{{SELECT num_attachments 
FROM table GROUP BY num_attachments}}} (but this would give extra output for 
rows containing more than one attachment).
  
- 
  == Generating a list of unique values ==
- 
  Here we use the fact that the key for a view result can be an array. Suppose 
you have a map that generates (key, value) pairs with many duplicates and you 
want to remove the duplicates. To do so, use {{{emit([key, value], null)}}} as 
the map output.
  
  Call this with ''group=true'' or you only get ''null''.
@@ -95, +81 @@

}
  }
  }}}
- 
  {{{#!highlight javascript
  // reduce
  function(keys, values) {
 return null;
  }
  }}}
+ This will give you results like
  
- This will give you results like
  {{{#!highlight javascript
  {rows:[
  {key:[thisparent,thatlink],value:null},
  {key:[thisparent,thatotherlink],value:null}
  ]}
  }}}
- 
- You can then get all the rows for the key ''thisparent'' with the view 
parameters 
''startkey=[''thisparent]endkey=[thisparent,{}]inclusive_end=false''
+ You can then get all the rows for the key ''thisparent'' with the view 
parameters 
''startkey=[thisparent]endkey=[thisparent,{}]inclusive_end=false''
  
  Note that the trick here is using the key for what you want to make unique. 
You can combine this with the counting above to get a count of duplicate values:
  
@@ -123, +107 @@

}
  }
  }}}
- 
  {{{#!highlight javascript
  // reduce
  function(keys, values) {
 return sum(values);
  }
  }}}
+ If you then want to know the total count for each parent, you can use the 
''group_level'' view parameter: 
''startkey=[thisparent]endkey=[thisparent,{}]inclusive_end=falsegroup_level=1''
- 
- If you then want to know the total count for each parent, you can use the 
''group_level'' view parameter:
- 
''startkey=[''thisparent]endkey=[thisparent,{}]inclusive_end=falsegroup_level=1''
  
  == Get contents of an object with specific attributes e.g. 
doc.objects.[0].attribute ==
- 
  {{{#!highlight javascript
  // map
  function(doc) {
@@ -144, +124 @@

}
  }
  }}}
+ == Arbitrarily query against any document property (uniview) ==
+ '''Note: This is not a generally recommended approach, as your view size 

[1/2] git commit: remove obsolete entry in .gitignore

2012-01-24 Thread randall
Updated Branches:
  refs/heads/1.2.x 32c702572 - c7765f657
  refs/heads/master fb3f2ae8b - 6282b5d03


remove obsolete entry in .gitignore


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/c7765f65
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/c7765f65
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/c7765f65

Branch: refs/heads/1.2.x
Commit: c7765f6574768caf2be2c98331263ab91182cda9
Parents: 32c7025
Author: Randall Leeds rand...@apache.org
Authored: Tue Jan 24 13:29:02 2012 -0800
Committer: Randall Leeds rand...@apache.org
Committed: Tue Jan 24 13:29:29 2012 -0800

--
 .gitignore |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/c7765f65/.gitignore
--
diff --git a/.gitignore b/.gitignore
index 365d963..cbf2b42 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,7 +45,6 @@ var/Makefile
 
 bin/couchdb
 bin/couchdb.1
-bin/couchjs
 bin/couch-config
 bin/couch-config_dev
 etc/couchdb/default.ini



[2/2] git commit: remove obsolete entry in .gitignore

2012-01-24 Thread randall
remove obsolete entry in .gitignore


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/6282b5d0
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/6282b5d0
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/6282b5d0

Branch: refs/heads/master
Commit: 6282b5d030ac74274fa1628a5a0b0e66293297b1
Parents: fb3f2ae
Author: Randall Leeds rand...@apache.org
Authored: Tue Jan 24 13:29:02 2012 -0800
Committer: Randall Leeds rand...@apache.org
Committed: Tue Jan 24 13:29:02 2012 -0800

--
 .gitignore |1 -
 1 files changed, 0 insertions(+), 1 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/6282b5d0/.gitignore
--
diff --git a/.gitignore b/.gitignore
index a24f0a1..f3bdc52 100644
--- a/.gitignore
+++ b/.gitignore
@@ -48,7 +48,6 @@ var/Makefile
 
 bin/couchdb
 bin/couchdb.1
-bin/couchjs
 bin/couch-config
 bin/couch-config_dev
 etc/couchdb/default.ini



[2/4] git commit: Prevent multiple updates to a single _local doc

2012-01-24 Thread davisp
Prevent multiple updates to a single _local doc

If a user uploads a two _local docs with the same docid in a _bulk_docs
request the updater will insert multiple entries into the local docs
btree. This patch avoids that by throwing an error if a user attempts
it.

This is an old bug that I caught and just added a fix for. I split it
out as its own patch to point out that its a bug fix that differs from
the old behvior.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/9d0db1b9
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/9d0db1b9
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/9d0db1b9

Branch: refs/heads/new-security-object
Commit: 9d0db1b923dba01b665674dc55ada47a4fe6146c
Parents: eb4138f
Author: Paul Joseph Davis dav...@apache.org
Authored: Mon Jan 23 17:56:18 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:14:07 2012 -0600

--
 src/couchdb/couch_db.erl |   10 ++
 1 files changed, 10 insertions(+), 0 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/9d0db1b9/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index a6903c4..be65f53 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -727,6 +727,16 @@ update_docs(Db, Docs, Options, interactive_edit) -
 end
 end, {[], []}, Docs2),
 
+% Prevent updating multiple _local docs in a single update
+% request. This relies on couch_db_updater not collecting
+% more than one update that contains _local docs but this
+% is still trigerable with a _bulk_docs request.
+UniqNRIds = lists:usort([Id || #doc{id=Id} - NonRepDocs0]),
+case length(UniqNRIds) == length(NonRepDocs0) of
+true - ok;
+false - throw({update_error, repeated_local_docs})
+end,
+
 {NonRepDocs, _} = new_revs(NonRepDocs0, [], []),
 
 DocBuckets = before_docs_update(Db, group_alike_docs(Docs3)),



[4/4] git commit: Implement _security as a _local doc

2012-01-24 Thread davisp
Implement _security as a _local doc

As per mailing list discussion on enabling the syncing of _security
objects this builds upon the previous commits to enable the agreed upon
strategy of giving a revision tree to the _security object.

The old API is maintained with identical in the normal single node case.
Though it is also now possible to update the _local/_security doc
directly using the normal HTTP document and _bulk_docs API's to edit the
doc directly.

This document is special cased like _design docs to disallow non-admins
from editing it.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/76fff259
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/76fff259
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/76fff259

Branch: refs/heads/new-security-object
Commit: 76fff259a62e1c2f443d625756d3f8d6c88ee6a8
Parents: 9d0db1b
Author: Paul Joseph Davis dav...@apache.org
Authored: Mon Jan 23 17:59:57 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:14:07 2012 -0600

--
 src/couchdb/couch_db.erl |   22 ++
 src/couchdb/couch_db.hrl |1 +
 src/couchdb/couch_db_updater.erl |   76 ++---
 3 files changed, 65 insertions(+), 34 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/76fff259/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index be65f53..987e8f7 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -359,21 +359,23 @@ 
check_is_member(#db{user_ctx=#user_ctx{name=Name,roles=Roles}=UserCtx}=Db) -
 end
 end.
 
-get_admins(#db{security=SecProps}) -
+get_admins(#db{security=Doc}) -
+#doc{body={SecProps}} = Doc,
 couch_util:get_value(admins, SecProps, {[]}).
 
-get_members(#db{security=SecProps}) -
+get_members(#db{security=Doc}) -
+#doc{body={SecProps}} = Doc,
 % we fallback to readers here for backwards compatibility
 couch_util:get_value(members, SecProps,
 couch_util:get_value(readers, SecProps, {[]})).
 
-get_security(#db{security=SecProps}) -
-{SecProps}.
+get_security(#db{security=SecDoc}) -
+SecDoc#doc.body.
 
-set_security(#db{update_pid=Pid}=Db, {NewSecProps}) when is_list(NewSecProps) 
-
+set_security(#db{security=Doc}=Db, {NewSecProps}) when is_list(NewSecProps) -
 check_is_admin(Db),
 ok = validate_security_object(NewSecProps),
-ok = gen_server:call(Pid, {set_security, NewSecProps}, infinity),
+{ok, _} = update_doc(Db, Doc#doc{body={NewSecProps}}, []),
 {ok, _} = ensure_full_commit(Db),
 ok;
 set_security(_, _) -
@@ -459,10 +461,12 @@ group_alike_docs([{Doc,Ref}|Rest], [Bucket|RestBuckets]) 
-
 
 validate_doc_update(#db{}=Db, #doc{id= _design/,_/binary}, 
_GetDiskDocFun) -
 catch check_is_admin(Db);
-validate_doc_update(#db{validate_doc_funs=[]}, _Doc, _GetDiskDocFun) -
-ok;
+validate_doc_update(Db, #doc{id= ?SECURITY_ID}, _GetDiskDocFun) -
+catch check_is_admin(Db);
 validate_doc_update(_Db, #doc{id= _local/,_/binary}, _GetDiskDocFun) -
 ok;
+validate_doc_update(#db{validate_doc_funs=[]}, _Doc, _GetDiskDocFun) -
+ok;
 validate_doc_update(Db, Doc, GetDiskDocFun) -
 DiskDoc = GetDiskDocFun(),
 JsonCtx = couch_util:json_user_ctx(Db),
@@ -731,7 +735,7 @@ update_docs(Db, Docs, Options, interactive_edit) -
 % request. This relies on couch_db_updater not collecting
 % more than one update that contains _local docs but this
 % is still trigerable with a _bulk_docs request.
-UniqNRIds = lists:usort([Id || #doc{id=Id} - NonRepDocs0]),
+UniqNRIds = lists:usort([Id || [{#doc{id=Id}, _}] - NonRepDocs0]),
 case length(UniqNRIds) == length(NonRepDocs0) of
 true - ok;
 false - throw({update_error, repeated_local_docs})

http://git-wip-us.apache.org/repos/asf/couchdb/blob/76fff259/src/couchdb/couch_db.hrl
--
diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl
index 65eb7f0..26ffe0d 100644
--- a/src/couchdb/couch_db.hrl
+++ b/src/couchdb/couch_db.hrl
@@ -11,6 +11,7 @@
 % the License.
 
 -define(LOCAL_DOC_PREFIX, _local/).
+-define(SECURITY_ID, _local/_security).
 -define(DESIGN_DOC_PREFIX0, _design).
 -define(DESIGN_DOC_PREFIX, _design/).
 -define(DEFAULT_COMPRESSION, snappy).

http://git-wip-us.apache.org/repos/asf/couchdb/blob/76fff259/src/couchdb/couch_db_updater.erl
--
diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl
index 862c48a..42b6460 100644
--- a/src/couchdb/couch_db_updater.erl
+++ b/src/couchdb/couch_db_updater.erl
@@ -67,14 +67,6 

[3/4] git commit: Replace _local doc sequence with revision trees

2012-01-24 Thread davisp
Replace _local doc sequence with revision trees

There are a number of cases that _local docs might need to be merged
between nodes. One motivating case is for clusters that might wish to
move _local docs across nodes to maintain replication checkpoints with
external CouchDB instances. The previous _local docs strategy of a
single linear sequence breaks down in this situation.

This new behavior should be indistinguishable from the previous behavior
assuming clients did not try and introspect the _rev value for _local
documents. It should be impossible for normal HTTP clients to introduce
different behavior than previously existed because there's no support
for non-linear updates at the HTTP level. This update is merely and
internal refactoring for special cases like clusters.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/eb4138f1
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/eb4138f1
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/eb4138f1

Branch: refs/heads/new-security-object
Commit: eb4138f196f15364e293128cacc2c5011bb28b69
Parents: 0ab5ebd
Author: Paul Joseph Davis dav...@apache.org
Authored: Thu Jan 19 18:10:05 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:14:07 2012 -0600

--
 src/couch_replicator/src/couch_replicator.erl |9 +-
 src/couchdb/couch_db.erl  |   21 +++-
 src/couchdb/couch_db_updater.erl  |  116 ++--
 3 files changed, 81 insertions(+), 65 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/eb4138f1/src/couch_replicator/src/couch_replicator.erl
--
diff --git a/src/couch_replicator/src/couch_replicator.erl 
b/src/couch_replicator/src/couch_replicator.erl
index 1f7c08a..53acfd5 100644
--- a/src/couch_replicator/src/couch_replicator.erl
+++ b/src/couch_replicator/src/couch_replicator.erl
@@ -580,15 +580,18 @@ fold_replication_logs([Db | Rest] = Dbs, Vsn, LogId, 
NewId, Rep, Acc) -
 fold_replication_logs(Dbs, Vsn - 1,
 ?l2b(?LOCAL_DOC_PREFIX ++ OldRepId), NewId, Rep, Acc);
 {error, not_found} -
+Doc0 = #doc{id = NewId},
+Doc1 = Doc0#doc{revs = {1, [couch_db:new_revid(Doc0)]}},
 fold_replication_logs(
-Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [#doc{id = NewId} | 
Acc]);
+Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Doc1 | Acc]);
 {ok, Doc} when LogId =:= NewId -
 fold_replication_logs(
 Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Doc | Acc]);
 {ok, Doc} -
-MigratedLog = #doc{id = NewId, body = Doc#doc.body},
+Log0 = #doc{id = NewId, body = Doc#doc.body},
+Log1 = Log0#doc{revs = {1, [couch_db:new_revid(Log0)]}},
 fold_replication_logs(
-Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [MigratedLog | Acc])
+Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Log1 | Acc])
 end.
 
 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/eb4138f1/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index ae21bfa..a6903c4 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -717,16 +717,18 @@ update_docs(Db, Docs, Options, interactive_edit) -
 
 % associate reference with each doc in order to track duplicates
 Docs2 = lists:map(fun(Doc) - {Doc, make_ref()} end,Docs),
-{Docs3, NonRepDocs} = lists:foldl(
+{Docs3, NonRepDocs0} = lists:foldl(
  fun({#doc{id=Id},_Ref}=Doc, {DocsAcc, NonRepDocsAcc}) -
 case Id of
 ?LOCAL_DOC_PREFIX, _/binary -
-{DocsAcc, [Doc | NonRepDocsAcc]};
+{DocsAcc, [[Doc] | NonRepDocsAcc]};
 Id-
 {[Doc | DocsAcc], NonRepDocsAcc}
 end
 end, {[], []}, Docs2),
 
+{NonRepDocs, _} = new_revs(NonRepDocs0, [], []),
+
 DocBuckets = before_docs_update(Db, group_alike_docs(Docs3)),
 
 case (Db#db.validate_doc_funs /= []) orelse
@@ -826,8 +828,9 @@ collect_results(UpdatePid, MRef, ResultsAcc) -
 end.
 
 write_and_commit(#db{update_pid=UpdatePid}=Db, DocBuckets1,
-NonRepDocs, Options0) -
+NonRepDocs1, Options0) -
 DocBuckets = prepare_doc_summaries(Db, DocBuckets1),
+NonRepDocs = prepare_doc_summaries(Db, NonRepDocs1),
 Options = set_commit_option(Options0),
 MergeConflicts = lists:member(merge_conflicts, Options),
 FullCommit = lists:member(full_commit, Options),
@@ -1182,9 +1185,15 @@ open_doc_revs_int(Db, IdRevs, Options) -
 
 open_doc_int(Db, ?LOCAL_DOC_PREFIX, _/binary = Id, Options) -
 case couch_btree:lookup(local_btree(Db), [Id]) of
-

[1/3] git commit: Implement _security as a _local doc

2012-01-24 Thread davisp
Updated Branches:
  refs/heads/new-security-object 76fff259a - e058fff59 (forced update)


Implement _security as a _local doc

As per mailing list discussion on enabling the syncing of _security
objects this builds upon the previous commits to enable the agreed upon
strategy of giving a revision tree to the _security object.

The old API is maintained with identical in the normal single node case.
Though it is also now possible to update the _local/_security doc
directly using the normal HTTP document and _bulk_docs API's to edit the
doc directly.

This document is special cased like _design docs to disallow non-admins
from editing it.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/e058fff5
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/e058fff5
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/e058fff5

Branch: refs/heads/new-security-object
Commit: e058fff599fb88e029155315072d47fe419984c8
Parents: c6ed253
Author: Paul Joseph Davis dav...@apache.org
Authored: Mon Jan 23 17:59:57 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:25:06 2012 -0600

--
 src/couchdb/couch_db.erl |   22 ++
 src/couchdb/couch_db.hrl |1 +
 src/couchdb/couch_db_updater.erl |   76 ++---
 3 files changed, 65 insertions(+), 34 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/e058fff5/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index be65f53..987e8f7 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -359,21 +359,23 @@ 
check_is_member(#db{user_ctx=#user_ctx{name=Name,roles=Roles}=UserCtx}=Db) -
 end
 end.
 
-get_admins(#db{security=SecProps}) -
+get_admins(#db{security=Doc}) -
+#doc{body={SecProps}} = Doc,
 couch_util:get_value(admins, SecProps, {[]}).
 
-get_members(#db{security=SecProps}) -
+get_members(#db{security=Doc}) -
+#doc{body={SecProps}} = Doc,
 % we fallback to readers here for backwards compatibility
 couch_util:get_value(members, SecProps,
 couch_util:get_value(readers, SecProps, {[]})).
 
-get_security(#db{security=SecProps}) -
-{SecProps}.
+get_security(#db{security=SecDoc}) -
+SecDoc#doc.body.
 
-set_security(#db{update_pid=Pid}=Db, {NewSecProps}) when is_list(NewSecProps) 
-
+set_security(#db{security=Doc}=Db, {NewSecProps}) when is_list(NewSecProps) -
 check_is_admin(Db),
 ok = validate_security_object(NewSecProps),
-ok = gen_server:call(Pid, {set_security, NewSecProps}, infinity),
+{ok, _} = update_doc(Db, Doc#doc{body={NewSecProps}}, []),
 {ok, _} = ensure_full_commit(Db),
 ok;
 set_security(_, _) -
@@ -459,10 +461,12 @@ group_alike_docs([{Doc,Ref}|Rest], [Bucket|RestBuckets]) 
-
 
 validate_doc_update(#db{}=Db, #doc{id= _design/,_/binary}, 
_GetDiskDocFun) -
 catch check_is_admin(Db);
-validate_doc_update(#db{validate_doc_funs=[]}, _Doc, _GetDiskDocFun) -
-ok;
+validate_doc_update(Db, #doc{id= ?SECURITY_ID}, _GetDiskDocFun) -
+catch check_is_admin(Db);
 validate_doc_update(_Db, #doc{id= _local/,_/binary}, _GetDiskDocFun) -
 ok;
+validate_doc_update(#db{validate_doc_funs=[]}, _Doc, _GetDiskDocFun) -
+ok;
 validate_doc_update(Db, Doc, GetDiskDocFun) -
 DiskDoc = GetDiskDocFun(),
 JsonCtx = couch_util:json_user_ctx(Db),
@@ -731,7 +735,7 @@ update_docs(Db, Docs, Options, interactive_edit) -
 % request. This relies on couch_db_updater not collecting
 % more than one update that contains _local docs but this
 % is still trigerable with a _bulk_docs request.
-UniqNRIds = lists:usort([Id || #doc{id=Id} - NonRepDocs0]),
+UniqNRIds = lists:usort([Id || [{#doc{id=Id}, _}] - NonRepDocs0]),
 case length(UniqNRIds) == length(NonRepDocs0) of
 true - ok;
 false - throw({update_error, repeated_local_docs})

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e058fff5/src/couchdb/couch_db.hrl
--
diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl
index 65eb7f0..26ffe0d 100644
--- a/src/couchdb/couch_db.hrl
+++ b/src/couchdb/couch_db.hrl
@@ -11,6 +11,7 @@
 % the License.
 
 -define(LOCAL_DOC_PREFIX, _local/).
+-define(SECURITY_ID, _local/_security).
 -define(DESIGN_DOC_PREFIX0, _design).
 -define(DESIGN_DOC_PREFIX, _design/).
 -define(DEFAULT_COMPRESSION, snappy).

http://git-wip-us.apache.org/repos/asf/couchdb/blob/e058fff5/src/couchdb/couch_db_updater.erl
--
diff --git a/src/couchdb/couch_db_updater.erl b/src/couchdb/couch_db_updater.erl
index 862c48a..42b6460 100644
--- 

[2/3] git commit: Prevent multiple updates to a single _local doc

2012-01-24 Thread davisp
Prevent multiple updates to a single _local doc

If a user uploads a two _local docs with the same docid in a _bulk_docs
request the updater will insert multiple entries into the local docs
btree. This patch avoids that by throwing an error if a user attempts
it.

This is an old bug that I caught and just added a fix for. I split it
out as its own patch to point out that its a bug fix that differs from
the old behvior.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/c6ed2538
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/c6ed2538
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/c6ed2538

Branch: refs/heads/new-security-object
Commit: c6ed2538749697bbbedfbf7ff32afa8a0c940e94
Parents: b96bea4
Author: Paul Joseph Davis dav...@apache.org
Authored: Mon Jan 23 17:56:18 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:25:06 2012 -0600

--
 src/couchdb/couch_db.erl |   10 ++
 1 files changed, 10 insertions(+), 0 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/c6ed2538/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index a6903c4..be65f53 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -727,6 +727,16 @@ update_docs(Db, Docs, Options, interactive_edit) -
 end
 end, {[], []}, Docs2),
 
+% Prevent updating multiple _local docs in a single update
+% request. This relies on couch_db_updater not collecting
+% more than one update that contains _local docs but this
+% is still trigerable with a _bulk_docs request.
+UniqNRIds = lists:usort([Id || #doc{id=Id} - NonRepDocs0]),
+case length(UniqNRIds) == length(NonRepDocs0) of
+true - ok;
+false - throw({update_error, repeated_local_docs})
+end,
+
 {NonRepDocs, _} = new_revs(NonRepDocs0, [], []),
 
 DocBuckets = before_docs_update(Db, group_alike_docs(Docs3)),



[3/3] git commit: Update _local docs to use revision trees

2012-01-24 Thread davisp
Update _local docs to use revision trees

There are a number of cases that _local docs might need to be merged
between nodes. One motivating case is for clusters that might wish to
move _local docs across nodes to maintain replication checkpoints with
external CouchDB instances. The previous _local docs strategy of a
single linear sequence breaks down in this situation.

This new behavior should be indistinguishable from the previous behavior
assuming clients did not try and introspect the _rev value for _local
documents. It should be impossible for normal HTTP clients to introduce
different behavior than previously existed because there's no support
for non-linear updates at the HTTP level. This update is merely and
internal refactoring for special cases like clusters.


Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/b96bea42
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/b96bea42
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/b96bea42

Branch: refs/heads/new-security-object
Commit: b96bea429a38655cb3efeb07f30f5925416a6524
Parents: 0ab5ebd
Author: Paul Joseph Davis dav...@apache.org
Authored: Thu Jan 19 18:10:05 2012 -0600
Committer: Paul Joseph Davis dav...@apache.org
Committed: Wed Jan 25 01:24:48 2012 -0600

--
 src/couch_replicator/src/couch_replicator.erl |9 +-
 src/couchdb/couch_db.erl  |   21 +++-
 src/couchdb/couch_db_updater.erl  |  116 ++--
 3 files changed, 81 insertions(+), 65 deletions(-)
--


http://git-wip-us.apache.org/repos/asf/couchdb/blob/b96bea42/src/couch_replicator/src/couch_replicator.erl
--
diff --git a/src/couch_replicator/src/couch_replicator.erl 
b/src/couch_replicator/src/couch_replicator.erl
index 1f7c08a..53acfd5 100644
--- a/src/couch_replicator/src/couch_replicator.erl
+++ b/src/couch_replicator/src/couch_replicator.erl
@@ -580,15 +580,18 @@ fold_replication_logs([Db | Rest] = Dbs, Vsn, LogId, 
NewId, Rep, Acc) -
 fold_replication_logs(Dbs, Vsn - 1,
 ?l2b(?LOCAL_DOC_PREFIX ++ OldRepId), NewId, Rep, Acc);
 {error, not_found} -
+Doc0 = #doc{id = NewId},
+Doc1 = Doc0#doc{revs = {1, [couch_db:new_revid(Doc0)]}},
 fold_replication_logs(
-Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [#doc{id = NewId} | 
Acc]);
+Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Doc1 | Acc]);
 {ok, Doc} when LogId =:= NewId -
 fold_replication_logs(
 Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Doc | Acc]);
 {ok, Doc} -
-MigratedLog = #doc{id = NewId, body = Doc#doc.body},
+Log0 = #doc{id = NewId, body = Doc#doc.body},
+Log1 = Log0#doc{revs = {1, [couch_db:new_revid(Log0)]}},
 fold_replication_logs(
-Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [MigratedLog | Acc])
+Rest, ?REP_ID_VERSION, NewId, NewId, Rep, [Log1 | Acc])
 end.
 
 

http://git-wip-us.apache.org/repos/asf/couchdb/blob/b96bea42/src/couchdb/couch_db.erl
--
diff --git a/src/couchdb/couch_db.erl b/src/couchdb/couch_db.erl
index ae21bfa..a6903c4 100644
--- a/src/couchdb/couch_db.erl
+++ b/src/couchdb/couch_db.erl
@@ -717,16 +717,18 @@ update_docs(Db, Docs, Options, interactive_edit) -
 
 % associate reference with each doc in order to track duplicates
 Docs2 = lists:map(fun(Doc) - {Doc, make_ref()} end,Docs),
-{Docs3, NonRepDocs} = lists:foldl(
+{Docs3, NonRepDocs0} = lists:foldl(
  fun({#doc{id=Id},_Ref}=Doc, {DocsAcc, NonRepDocsAcc}) -
 case Id of
 ?LOCAL_DOC_PREFIX, _/binary -
-{DocsAcc, [Doc | NonRepDocsAcc]};
+{DocsAcc, [[Doc] | NonRepDocsAcc]};
 Id-
 {[Doc | DocsAcc], NonRepDocsAcc}
 end
 end, {[], []}, Docs2),
 
+{NonRepDocs, _} = new_revs(NonRepDocs0, [], []),
+
 DocBuckets = before_docs_update(Db, group_alike_docs(Docs3)),
 
 case (Db#db.validate_doc_funs /= []) orelse
@@ -826,8 +828,9 @@ collect_results(UpdatePid, MRef, ResultsAcc) -
 end.
 
 write_and_commit(#db{update_pid=UpdatePid}=Db, DocBuckets1,
-NonRepDocs, Options0) -
+NonRepDocs1, Options0) -
 DocBuckets = prepare_doc_summaries(Db, DocBuckets1),
+NonRepDocs = prepare_doc_summaries(Db, NonRepDocs1),
 Options = set_commit_option(Options0),
 MergeConflicts = lists:member(merge_conflicts, Options),
 FullCommit = lists:member(full_commit, Options),
@@ -1182,9 +1185,15 @@ open_doc_revs_int(Db, IdRevs, Options) -
 
 open_doc_int(Db, ?LOCAL_DOC_PREFIX, _/binary = Id, Options) -
 case couch_btree:lookup(local_btree(Db), [Id]) of
-[{ok,