3634 John David Duncan 2011-11-07 [merge]
merge from local working branch
added:
mysql-test/suite/ndb_memcache/r/unique_idx.result
mysql-test/suite/ndb_memcache/t/unique_idx.test
modified:
storage/ndb/memcache/include/KeyPrefix.h
storage/ndb/memcache/include/QueryPlan.h
storage/ndb/memcache/include/workitem.h
storage/ndb/memcache/scripts/pmpstack.awk
storage/ndb/memcache/src/QueryPlan.cc
storage/ndb/memcache/src/ndb_worker.cc
3633 John David Duncan 2011-11-07 [merge]
merge from local working branch
modified:
storage/ndb/memcache/include/int3korr.h
=== added file 'mysql-test/suite/ndb_memcache/r/unique_idx.result'
--- a/mysql-test/suite/ndb_memcache/r/unique_idx.result 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb_memcache/r/unique_idx.result 2011-11-07 21:54:07 +0000
@@ -0,0 +1,7 @@
+SELECT * FROM ndbmemcache.test_unique_idx;
+pkey mkey val
+1 key1 Quotidien
+2 key2 Passable
+3 key3 Assez bien
+4 key4 Pas trop mal...
+DELETE FROM ndbmemcache.test_unique_idx;
=== added file 'mysql-test/suite/ndb_memcache/t/unique_idx.test'
--- a/mysql-test/suite/ndb_memcache/t/unique_idx.test 1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/ndb_memcache/t/unique_idx.test 2011-11-07 21:54:07 +0000
@@ -0,0 +1,115 @@
+################################################################
+# Test access via unique index
+#
+# Write-access via unique index is subject to some restrictions:
+#
+# (1) Inserts are not allowed; they will fail with NOT_FOUND
+# (2) Updates that do not contain the PK column are allowed
+# (3) Updates that contain the PK column are allowed if the PK value
+# does not change, but attempts to change the PK fail with NOT_STORED.
+
+
+--source suite/ndb_memcache/include/have_memcache.inc
+--source suite/ndb_memcache/include/memcached_wait_for_ready.inc
+
+
+#
+# Configuration change for this test
+#
+
+--disable_query_log
+--disable_result_log
+USE ndbmemcache;
+CREATE TABLE test_unique_idx (pkey int PRIMARY KEY,
+ mkey char(40),
+ val varchar(200),
+ UNIQUE INDEX (mkey)
+ ) ENGINE=ndbcluster;
+
+INSERT INTO containers (name, db_schema, db_table, key_columns, value_columns)
+ VALUES("tt_uidx_pk", "ndbmemcache", "test_unique_idx", "pkey", "mkey,val"),
+ ("tt_uidx_rd", "ndbmemcache", "test_unique_idx", "mkey", "pkey,val"),
+ ("tt_uidx_uk", "ndbmemcache", "test_unique_idx", "mkey", "val");
+
+INSERT INTO key_prefixes(server_role_id, key_prefix, policy, container)
+ VALUES(0, "tup:", "ndb-only", "tt_uidx_pk"),
+ (0, "tur:", "ndb-only", "tt_uidx_rd"),
+ (0, "tui:", "ndb-only", "tt_uidx_uk");
+
+UPDATE memcache_server_roles set update_timestamp = NOW() where role_id = 0;
+--enable_query_log
+--enable_result_log
+
+#
+# Memcache operations for this test
+#
+
+--perl
+
+use strict;
+use Carp;
+use lib "lib";
+use My::Memcache;
+my $mc = My::Memcache->new();
+my $port = $ENV{MTR_BUILD_THREAD} * 10 + 10000 + 8;
+my $r = $mc->connect("localhost",$port);
+
+my $cf_gen = $mc->wait_for_reconf();
+
+if($cf_gen == 0) {
+ Carp::confess("FAILED WAIT_FOR_RECONF");
+}
+
+# 1: SET on primary key
+$mc->set("tup:1","key1\tSuperbe!") || Carp::confess("Failed test 1.A");
+$mc->set("tup:2","key2\tIncroyable!") || Carp::confess("Failed test 1.B");
+$mc->set("tup:3","key3\tTres bien fait");
+$mc->set("tup:4","key4\tPas mal");
+
+# 2: GET on primary key
+($mc->get("tup:1") == "key1\tSuperbe!") || Carp::confess("Failed test 2.A");
+($mc->get("tup:2") == "key2\tIncroyable!")|| Carp::confess("Failed test 2.B");
+
+# 3: GET via unique key (two value columns)
+($mc->get("tur:key1") == "1\tSuperbe!") || Carp::confess("Failed test 3.");
+
+# 4: GET via unique key (one value column)
+($mc->get("tui:key2") == "Incroyable!") || Carp::confess("Failed test 4.");
+
+# 5. SET via unique key (one value column, not part of primary key)
+$mc->set("tui:key3", "Assez bien") || Carp::confess("Failed test 5.A");
+$mc->set("tui:key4", "Pas trop mal...") || Carp::confess("Failed test 5.B");
+
+# 6. REPLACE via unique key (one value column, not part of primary key)
+$mc->replace("tui:key2", "Passable") || Carp::confess("Failed test 6");
+
+# 7. Inserts via unique key access fail with NOT_FOUND:
+# (A) SET
+($mc->set("tui:key5", "rien") == 0) || Carp::confess("Test 7.A SET should fail");
+($mc->{error} =~ "NOT_FOUND") || Carp::confess("Test 7.A expected NOT_FOUND");
+
+# (B) ADD
+($mc->add("tui:key6", "rien") == 0) || Carp::confess("Test 7.B ADD should fail");
+($mc->{error} =~ "NOT_FOUND") || Carp::confess("Test 7.B expected NOT_FOUND");
+
+# 8. Update via unique key succeeds if PK is equal to old PK
+$mc->set("tur:key1", "1\tQuotidien") || Carp::confess("Failed test 8.A");
+($mc->get("tui:key1") == "Quotidien") || Carp::confess("Failed test 8.B");
+
+# 9. Attempt to change PK fails with NOT_STORED
+($mc->set("tur:key3", "5\tJamais!") == 0) || Carp::confess("Test 9 SET should fail.");
+($mc->{error} =~ "NOT_STORED") || Carp::confess("Test 9 expected NOT_STORED");
+
+EOF
+
+# At the end of the test the values should be
+# 1 Quotidien
+# 2 Passable
+# 3 Assez bien
+# 4 Pas trop mal...
+
+
+--sorted_result
+SELECT * FROM ndbmemcache.test_unique_idx;
+DELETE FROM ndbmemcache.test_unique_idx;
+
=== modified file 'storage/ndb/memcache/include/KeyPrefix.h'
--- a/storage/ndb/memcache/include/KeyPrefix.h 2011-09-12 10:05:07 +0000
+++ b/storage/ndb/memcache/include/KeyPrefix.h 2011-11-07 21:54:07 +0000
@@ -22,7 +22,7 @@
#include <stdio.h>
-/***** This section defines a data structures available to C. ***/
+/***** This section defines data structures available to C. ***/
/* The prefix_info_t is the compacted form of the parts of the
KeyPrefix that must be available to C code.
*/
=== modified file 'storage/ndb/memcache/include/QueryPlan.h'
--- a/storage/ndb/memcache/include/QueryPlan.h 2011-09-30 16:22:30 +0000
+++ b/storage/ndb/memcache/include/QueryPlan.h 2011-11-07 21:54:07 +0000
@@ -47,16 +47,16 @@ class QueryPlan {
QueryPlan() : initialized(0) {};
QueryPlan(Ndb *, const TableSpec *, PlanOpts opts = NoOptions);
~QueryPlan();
- bool keyIsPrimaryKey() const;
void debug_dump() const;
/* public instance variables */
bool initialized;
- bool dup_numbers;
+ bool dup_numbers; /* dup_numbers mode for ascii incr/decr */
+ bool pk_access; /* access by primary key */
+ bool is_scan;
const TableSpec *spec;
NdbDictionary::Dictionary *dict;
const NdbDictionary::Table *table;
- bool is_scan;
short cas_column_id;
short math_column_id;
unsigned int static_flags;
@@ -74,6 +74,7 @@ class QueryPlan {
private:
/* Private methods */
const NdbDictionary::Index * chooseIndex();
+ bool keyIsPrimaryKey() const;
/* Private instance variables */
Ndb *db;
=== modified file 'storage/ndb/memcache/include/workitem.h'
--- a/storage/ndb/memcache/include/workitem.h 2011-10-01 01:01:07 +0000
+++ b/storage/ndb/memcache/include/workitem.h 2011-11-07 21:54:07 +0000
@@ -45,11 +45,11 @@ typedef struct workitem {
unsigned verb : 4; /*! READ, DELETE, ADD, STORE, etc. */
unsigned math_incr : 1; /*! incr, or decr ? */
unsigned math_create : 1; /*! create record if not existing */
- unsigned _unused_1 : 1; /*! (formerly was is_sync) */
+ unsigned _unused_1 : 1; /*! */
unsigned has_value : 1; /*! are we able to use a no-copy value? */
unsigned retries : 3; /*! how many times this job has been retried */
unsigned complete : 1; /*! is this operation finished? */
- unsigned broker : 2; /*! for use by the flex scheduler */
+ unsigned _unused_2 : 2; /*! */
unsigned reschedule : 1; /*! inform scheduler to send and poll again */
unsigned cas_owner : 1; /*! set if this engine owns the CAS ID */
} base;
=== modified file 'storage/ndb/memcache/scripts/pmpstack.awk'
--- a/storage/ndb/memcache/scripts/pmpstack.awk 2011-09-12 10:05:07 +0000
+++ b/storage/ndb/memcache/scripts/pmpstack.awk 2011-11-07 21:54:07 +0000
@@ -23,7 +23,6 @@
function label(name) {
if(thr == "event") event[name] += $1;
else if(thr == "commit") commit[name] += $1;
- else if(thr == "broker") broker[name] += $1;
else if(thr == "send") send[name] += $1;
else if(thr == "poll") poll[name] += $1;
}
@@ -33,9 +32,7 @@ function label(name) {
{ thr="x" } # undetermined
/event_base_loop,worker_libevent/ { event["total"] += $1; thr="event" }
-/run_commit_thread/ { commit["total"] += $1; thr="commit" }
/run_ndb_commit_thread/ { commit["total"] += $1; thr="commit" }
-/run_broker_thread/ { broker["total"] += $1; thr="broker" }
/run_ndb_send_thread/ { send["total"] += $1 ; thr="send" }
/run_ndb_poll_thread/ { poll["total"] += $1 ; thr="poll" }
@@ -81,11 +78,6 @@ END {
"Event", (event[i] / event["total"]) * 100, i)
printf("\n");
- for(i in broker) if (i != "total")
- printf("%s\t%.2f%%\t%s\n",
- "Broker", (broker[i] / broker["total"]) * 100, i)
- if(broker["total"]) printf("\n");
-
for(i in commit) if(i != "total")
printf("%s\t%.2f%%\t%s\n",
"Commit", (commit[i] / commit["total"]) * 100, i)
=== modified file 'storage/ndb/memcache/src/QueryPlan.cc'
--- a/storage/ndb/memcache/src/QueryPlan.cc 2011-10-14 08:26:28 +0000
+++ b/storage/ndb/memcache/src/QueryPlan.cc 2011-11-07 21:54:07 +0000
@@ -125,8 +125,11 @@ QueryPlan::QueryPlan(Ndb *my_ndb, const
math_mask_i[this_col_id >> 3] |= (1 << (this_col_id & 7));
}
+ /* Primary Key access path? */
+ pk_access = keyIsPrimaryKey();
+
/* Choose an access path and complete the key record*/
- if(keyIsPrimaryKey() && ! (opts == PKScan)) {
+ if(pk_access && ! (opts == PKScan)) {
op_ok = key_record->complete(dict, table);
}
else {
@@ -232,6 +235,7 @@ void QueryPlan::debug_dump() const {
}
}
+
bool QueryPlan::keyIsPrimaryKey() const {
if(spec->nkeycols == table->getNoOfPrimaryKeys()) {
for(int i = 0 ; i < spec->nkeycols ; i++)
=== modified file 'storage/ndb/memcache/src/ndb_worker.cc'
--- a/storage/ndb/memcache/src/ndb_worker.cc 2011-10-07 20:38:22 +0000
+++ b/storage/ndb/memcache/src/ndb_worker.cc 2011-11-07 21:54:07 +0000
@@ -103,6 +103,9 @@ status_block status_block_bad_add =
status_block status_block_bad_replace =
{ ENGINE_NOT_STORED, "Tuple not found" };
+status_block status_block_idx_insert =
+ { ENGINE_NOT_STORED, "Cannot insert via unique index" };
+
void worker_set_cas(ndb_pipeline *p, uint64_t *cas) {
/* Be careful here -- ndbmc_atomic32_t might be a signed type.
@@ -350,23 +353,33 @@ op_status_t worker_do_read(workitem *wqi
NdbTransaction *tx = op.startTransaction(wqitem->ndb_instance->db);
DEBUG_ASSERT(tx);
- if(! op.readTuple(tx)) {
+ bool op_is_read_before_write;
+ ndb_async_callback *next_op;
+
+ if (wqitem->base.verb == OPERATION_APPEND || wqitem->base.verb == OPERATION_PREPEND) {
+ op_is_read_before_write = true;
+ next_op = rewrite_callback;
+ }
+ else {
+ op_is_read_before_write = false;
+ next_op = DB_callback;
+ }
+
+ /* Simple primary key reads use a SimpleRead lock.
+ Unique index reads need a Read lock.
+ APPEND and PREPEND need an Exclusive lock. */
+ NdbOperation::LockMode lockmode = NdbOperation::LM_SimpleRead;
+ if(op_is_read_before_write) lockmode = NdbOperation::LM_Exclusive;
+ else if(! plan->pk_access) lockmode = NdbOperation::LM_Read;
+
+ if(! op.readTuple(tx, lockmode)) {
logger->log(LOG_WARNING, 0, "readTuple(): %s\n", tx->getNdbError().message);
tx->close();
return op_failed;
}
/* Save the workitem in the transaction and prepare for async execution */
- if(wqitem->base.verb == OPERATION_APPEND || wqitem->base.verb == OPERATION_PREPEND)
- {
- DEBUG_PRINT("In read() portion of APPEND. Value = %s",
- hash_item_get_data(wqitem->cache_item));
- tx->executeAsynchPrepare(NdbTransaction::NoCommit, rewrite_callback, (void *) wqitem);
- }
- else
- {
- tx->executeAsynchPrepare(NdbTransaction::Commit, DB_callback, (void *) wqitem);
- }
+ tx->executeAsynchPrepare(NdbTransaction::NoCommit, next_op, (void *) wqitem);
return op_async_prepared;
}
@@ -551,6 +564,10 @@ void DB_callback(int result, NdbTransact
if(wqitem->cas) * wqitem->cas = 0ULL;
return_status = & status_block_bad_add;
}
+ /* Attempt to insert via unique index access */
+ else if(tx->getNdbError().code == 897) {
+ return_status = & status_block_idx_insert;
+ }
/* Some other error */
else {
DEBUG_PRINT("[%d]: %s",
@@ -916,7 +933,7 @@ ENGINE_ERROR_CODE ndb_flush_all(ndb_pipe
Ndb_cluster_connection *conn = pool->getMainConnection();
NdbInstance inst(conn, 128);
QueryPlan plan(inst.db, pfx->table);
- if(plan.keyIsPrimaryKey()) {
+ if(plan.pk_access) {
// To flush, scan the table and delete every row
DEBUG_PRINT("prefix %d - deleting from %s", i, pfx->table->table_name);
scan_delete(&inst, &plan);
No bundle (reason: useless for push emails).
| Thread |
|---|
| • bzr push into mysql-5.5-cluster branch (john.duncan:3633 to 3634) | John David Duncan | 9 Nov |