summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGreg Studer <greg@10gen.com>2014-02-06 12:14:53 -0500
committerGreg Studer <greg@10gen.com>2014-02-10 12:14:34 -0500
commit5d94703d7dbbf99de25152e69aacf47b4d09c2d4 (patch)
treeb6cc38cd351303f32a74336ef1434689eb84b98b
parent5999bc487e0b5a80c26676f396ba2544d9fadd5d (diff)
downloadmongo-5d94703d7dbbf99de25152e69aacf47b4d09c2d4.tar.gz
SERVER-12127 test of single write results, example of using new write command mode
-rw-r--r--jstests/core/write_result.js178
-rw-r--r--src/mongo/shell/collection.js43
-rw-r--r--src/mongo/shell/mongo.js4
3 files changed, 213 insertions, 12 deletions
diff --git a/jstests/core/write_result.js b/jstests/core/write_result.js
new file mode 100644
index 00000000000..881b91d2694
--- /dev/null
+++ b/jstests/core/write_result.js
@@ -0,0 +1,178 @@
+//
+// Tests the behavior of single writes using write commands
+//
+
+var coll = db.write_result;
+coll.drop();
+
+assert(coll.getMongo().useWriteCommands());
+
+var result = null;
+
+//
+// Basic insert
+coll.remove({});
+printjson( result = coll.insert({ foo : "bar" }) );
+assert.eq(result.nInserted, 1);
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 0);
+assert.eq(result.nModified, 0);
+assert.eq(result.nRemoved, 0);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 1);
+
+//
+// Basic upsert (using save)
+coll.remove({});
+var id = new ObjectId();
+printjson( result = coll.save({ _id : id, foo : "bar" }) );
+assert.eq(result.nInserted, 0);
+assert.eq(result.nUpserted, 1);
+assert.eq(result.nUpdated, 0);
+assert.eq(result.nModified, 0);
+assert.eq(result.nRemoved, 0);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert.eq(result.getUpsertedId()._id, id);
+assert.eq(coll.count(), 1);
+
+//
+// Basic update
+coll.remove({});
+coll.insert({ foo : "bar" });
+printjson( result = coll.update({ foo : "bar" }, { $set : { foo : "baz" } }) );
+assert.eq(result.nInserted, 0);
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 1);
+assert.eq(result.nModified, 1);
+assert.eq(result.nRemoved, 0);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 1);
+
+//
+// Basic multi-update
+coll.remove({});
+coll.insert({ foo : "bar" });
+coll.insert({ foo : "bar", set : ['value'] });
+printjson( result = coll.update({ foo : "bar" },
+ { $addToSet : { set : 'value' } },
+ { multi : true }) );
+assert.eq(result.nInserted, 0);
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 2);
+assert.eq(result.nModified, 1);
+assert.eq(result.nRemoved, 0);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 2);
+
+//
+// Basic remove
+coll.remove({});
+coll.insert({ foo : "bar" });
+printjson( result = coll.remove({}) );
+assert.eq(result.nInserted, 0);
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 0);
+assert.eq(result.nModified, 0);
+assert.eq(result.nRemoved, 1);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 0);
+
+//
+// Insert with error
+coll.remove({});
+var id = new ObjectId();
+coll.insert({ _id : id, foo : "bar" });
+printjson( result = coll.insert({ _id : id, foo : "baz" }) );
+assert.eq(result.nInserted, 0);
+assert(result.getWriteError());
+assert(result.getWriteError().errmsg);
+assert(!result.getWriteConcernError());
+assert.eq(coll.count(), 1);
+
+//
+// Update with error
+coll.remove({});
+coll.insert({ foo : "bar" });
+printjson( result = coll.update({ foo : "bar" }, { $invalid : "expr" }) );
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 0);
+assert.eq(result.nModified, 0);
+assert(result.getWriteError());
+assert(result.getWriteError().errmsg);
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 1);
+
+//
+// Multi-update with error
+coll.remove({});
+var id = new ObjectId();
+for (var i = 0; i < 10; ++i) coll.insert({ value : NumberInt(i) });
+coll.insert({ value : "not a number" });
+// $bit operator fails when the field is not integer
+// Note that multi-updates do not currently report partial stats if they fail
+printjson( result = coll.update({},
+ { $bit : { value : { and : NumberInt(0) } } },
+ { multi : true }) );
+assert.eq(result.nUpserted, 0);
+assert.eq(result.nUpdated, 0);
+assert.eq(result.nModified, 0);
+assert(result.getWriteError());
+assert(result.getWriteError().errmsg);
+assert(!result.getUpsertedId());
+assert.eq(coll.count(), 11);
+
+//
+// Bulk insert
+coll.remove({});
+printjson( result = coll.insert([{ foo : "bar" }, { foo : "baz" }]) );
+assert.eq(result.nInserted, 2);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert.eq(coll.count(), 2);
+
+//
+// Bulk insert with error
+coll.remove({});
+var id = new ObjectId();
+// Second insert fails with duplicate _id
+printjson( result = coll.insert([{ _id : id, foo : "bar" },
+ { _id : id, foo : "baz" }]) );
+assert.eq(result.nInserted, 1);
+assert(result.getWriteError());
+assert(!result.getWriteConcernError());
+assert.eq(coll.count(), 1);
+
+//
+// Custom write concern
+// (More detailed write concern tests require custom/replicated servers)
+coll.remove({});
+coll.setWriteConcern({ w : "majority" });
+printjson( result = coll.insert({ foo : "bar" }) );
+assert.eq(result.nInserted, 1);
+assert(!result.getWriteError());
+assert(!result.getWriteConcernError());
+assert.eq(coll.count(), 1);
+coll.unsetWriteConcern();
+
+//
+// Write concern error
+// NOTE: Non-throwing write concern failures require replication to trigger
+coll.remove({});
+coll.setWriteConcern({ w : 2 });
+assert.throws( function() {
+ printjson( coll.insert({ foo : "bar" }) );
+});
+assert.eq(coll.count(), 0);
+coll.unsetWriteConcern();
+
+
+
diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js
index 5a9b65de36d..bed1174b2ea 100644
--- a/src/mongo/shell/collection.js
+++ b/src/mongo/shell/collection.js
@@ -72,6 +72,8 @@ DBCollection.prototype.help = function () {
print("\tdb." + shortName + ".getShardVersion() - only for use with sharding");
print("\tdb." + shortName + ".getShardDistribution() - prints statistics about data distribution in the cluster");
print("\tdb." + shortName + ".getSplitKeysForChunks( <maxChunkSize> ) - calculates split points over all chunks and returns splitter function");
+ print("\tdb." + shortName + ".setWriteConcern( <write concern doc> ) - sets the write concern for writes to the collection");
+ print("\tdb." + shortName + ".unsetWriteConcern( <write concern doc> ) - unsets the write concern for writes to the collection");
// print("\tdb." + shortName + ".getDiskStorageStats({...}) - prints a summary of disk usage statistics");
// print("\tdb." + shortName + ".getPagesInRAM({...}) - prints a summary of storage pages currently in physical memory");
return __magicNoPrint;
@@ -211,9 +213,8 @@ DBCollection.prototype.insert = function( obj , options, _allow_dot ){
}
var writeConcern = null;
- if (this._mongo.getWriteConcern()) {
- writeConcern = this._mongo.getWriteConcern().toJSON();
- }
+ if (this.getWriteConcern())
+ writeConcern = this.getWriteConcern().toJSON();
result = batch.execute(writeConcern).toSingleResult();
}
@@ -268,9 +269,8 @@ DBCollection.prototype.remove = function( t , justOne ){
}
var writeConcern = null;
- if (this._mongo.getWriteConcern()) {
- writeConcern = this._mongo.getWriteConcern().toJSON();
- }
+ if (this.getWriteConcern())
+ writeConcern = this.getWriteConcern().toJSON();
result = batch.execute(writeConcern).toSingleResult();
}
@@ -332,9 +332,8 @@ DBCollection.prototype.update = function( query , obj , upsert , multi ){
}
var writeConcern = null;
- if (this._mongo.getWriteConcern()) {
- writeConcern = this._mongo.getWriteConcern().toJSON();
- }
+ if (this.getWriteConcern())
+ writeConcern = this.getWriteConcern().toJSON();
result = batch.execute(writeConcern).toSingleResult();
}
@@ -1366,7 +1365,31 @@ DBCollection.prototype.getPlanCache = function() {
return new PlanCache( this );
}
-// plan cache commands
+// Overrides connection-level settings.
+//
+
+DBCollection.prototype.setWriteConcern = function( wc ) {
+ if ( wc instanceof WriteConcern ) {
+ this._writeConcern = wc;
+ }
+ else {
+ this._writeConcern = new WriteConcern( wc );
+ }
+};
+
+DBCollection.prototype.getWriteConcern = function() {
+ if (this._writeConcern)
+ return this._writeConcern;
+
+ if (this._mongo.getWriteConcern())
+ return this._mongo.getWriteConcern();
+
+ return null;
+};
+
+DBCollection.prototype.unsetWriteConcern = function() {
+ delete this._writeConcern;
+};
/**
* PlanCache
diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js
index 05969828bab..6dc3d9da064 100644
--- a/src/mongo/shell/mongo.js
+++ b/src/mongo/shell/mongo.js
@@ -181,8 +181,8 @@ Mongo.prototype.useWriteCommands = function() {
};
//
-// Write Concern can be set at the connection level, and is used for all write operations
-// TODO: (unless overridden)
+// Write Concern can be set at the connection level, and is used for all write operations unless
+// overridden at the collection level.
//
Mongo.prototype.setWriteConcern = function( wc ) {