summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien F. Katz <damien@apache.org>2008-08-08 21:06:29 +0000
committerDamien F. Katz <damien@apache.org>2008-08-08 21:06:29 +0000
commitf2275fd25463764ea059b32ffb689baeeebc1ca1 (patch)
treea97ae4f116446f617f2b9339762dbb5b5bee7dee
parenta33cf09319d0b174ec9c509c815da160b7091ab3 (diff)
Idempotent document creation support, new HTTP api to generate UUIDs and support in the couch.js library for using them. Creating uuids client side ensure that document creation happens only once, despite automatic network retries.
git-svn-id: https://svn.apache.org/repos/asf/incubator/couchdb/trunk@684092 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--share/www/script/couch.js50
-rw-r--r--share/www/script/couch_tests.js36
-rw-r--r--src/couchdb/couch_httpd.erl13
3 files changed, 89 insertions, 10 deletions
diff --git a/share/www/script/couch.js b/share/www/script/couch.js
index 38c9cf34..2f15737d 100644
--- a/share/www/script/couch.js
+++ b/share/www/script/couch.js
@@ -42,18 +42,14 @@ function CouchDB(name) {
this.save = function(doc, options) {
var req;
if (doc._id == undefined)
- req = request("POST", this.uri + encodeOptions(options), {
- body: JSON.stringify(doc)
- });
- else
- req = request("PUT", this.uri + encodeURIComponent(doc._id) + encodeOptions(options), {
- body: JSON.stringify(doc)
- });
+ doc._id = CouchDB.newUuids(1)[0];
+
+ req = request("PUT", this.uri + encodeURIComponent(doc._id) + encodeOptions(options), {
+ body: JSON.stringify(doc)
+ });
var result = JSON.parse(req.responseText);
if (req.status != 201)
throw result;
- // set the _id and _rev members on the input object, for caller convenience.
- doc._id = result.id;
doc._rev = result.rev;
return result;
}
@@ -91,6 +87,18 @@ function CouchDB(name) {
}
this.bulkSave = function(docs, options) {
+ // first prepoulate the UUIDs for new documents
+ var newCount = 0
+ for (var i=0; i<docs.length; i++) {
+ if (docs[i]._id == undefined)
+ newCount++;
+ }
+ var newUuids = CouchDB.newUuids(docs.length);
+ var newCount = 0
+ for (var i=0; i<docs.length; i++) {
+ if (docs[i]._id == undefined)
+ docs[i]._id = newUuids.pop();
+ }
var req = request("POST", this.uri + "_bulk_docs" + encodeOptions(options), {
body: JSON.stringify({"docs": docs})
});
@@ -98,7 +106,6 @@ function CouchDB(name) {
if (req.status != 201)
throw result;
for (var i = 0; i < docs.length; i++) {
- docs[i]._id = result.new_revs[i].id;
docs[i]._rev = result.new_revs[i].rev;
}
return result;
@@ -232,3 +239,26 @@ CouchDB.request = function(method, uri, options) {
req.send(options.body || "");
return req;
}
+
+CouchDB.uuids_cache = [];
+
+CouchDB.newUuids = function(n) {
+ if (CouchDB.uuids_cache.length >= n) {
+ var uuids = CouchDB.uuids_cache.slice(CouchDB.uuids_cache.length - n);
+ if(CouchDB.uuids_cache.length - n == 0) {
+ CouchDB.uuids_cache = [];
+ } else {
+ CouchDB.uuids_cache =
+ CouchDB.uuids_cache.slice(0, CouchDB.uuids_cache.length - n);
+ }
+ return uuids;
+ } else {
+ var req = CouchDB.request("POST", "/_uuids?count=" + (100 + n));
+ var result = JSON.parse(req.responseText);
+ if (req.status != 200)
+ throw result;
+ CouchDB.uuids_cache =
+ CouchDB.uuids_cache.concat(result.uuids.slice(0, 100));
+ return result.uuids.slice(100);
+ }
+ }
diff --git a/share/www/script/couch_tests.js b/share/www/script/couch_tests.js
index 539b9a12..08c1bbe9 100644
--- a/share/www/script/couch_tests.js
+++ b/share/www/script/couch_tests.js
@@ -194,6 +194,42 @@ var tests = {
}
},
+ uuids: function(debug) {
+ var db = new CouchDB("test_suite_db");
+ db.deleteDb();
+ db.createDb();
+ if (debug) debugger;
+
+ // a single UUID without an explicit count
+ var xhr = CouchDB.request("POST", "/_uuids");
+ T(xhr.status == 200);
+ var result = JSON.parse(xhr.responseText);
+ T(result.uuids.length == 1);
+ var first = result.uuids[0];
+
+ // a single UUID with an explicit count
+ xhr = CouchDB.request("POST", "/_uuids?count=1");
+ T(xhr.status == 200);
+ result = JSON.parse(xhr.responseText);
+ T(result.uuids.length == 1);
+ var second = result.uuids[0];
+ T(first != second);
+
+ // no collisions with 1,000 UUIDs
+ xhr = CouchDB.request("POST", "/_uuids?count=1000");
+ T(xhr.status == 200);
+ result = JSON.parse(xhr.responseText);
+ T( result.uuids.length == 1000 );
+ var seen = {};
+ for(var i in result.uuids) {
+ var id = result.uuids[i];
+ T(seen[id] === undefined);
+ seen[id] = 1;
+ }
+
+ // check our library
+ },
+
bulk_docs: function(debug) {
var db = new CouchDB("test_suite_db");
db.deleteDb();
diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl
index 85fbe868..7b926019 100644
--- a/src/couchdb/couch_httpd.erl
+++ b/src/couchdb/couch_httpd.erl
@@ -97,6 +97,8 @@ handle_request0(Req, DocumentRoot, Method, Path) ->
handle_replicate_request(Req, Method);
"/_restart" ->
handle_restart_request(Req, Method);
+ "/_uuids" ->
+ handle_uuids_request(Req, Method);
"/_utils" ->
{ok, Req:respond({301, [
{"Location", "/_utils/"}
@@ -148,6 +150,17 @@ handle_restart_request(Req, 'POST') ->
handle_restart_request(_Req, _Method) ->
throw({method_not_allowed, "POST"}).
+handle_uuids_request(Req, 'POST') ->
+ Count = list_to_integer(proplists:get_value("count", Req:parse_qs(), "1")),
+ % generate the uuids
+ UUIDs = [ couch_util:new_uuid() || _ <- lists:seq(1,Count)],
+ % send a JSON response
+ send_json(Req, {obj, [{"uuids", list_to_tuple(UUIDs)}]});
+
+handle_uuids_request(_Req, _Method) ->
+ throw({method_not_allowed, "POST"}).
+
+
% Database request handlers
handle_db_request(Req, Method, {Path}) ->