bool SingleKeyspaceDB::Add(KeyspaceOp* op) { // Log_Trace(); bool isWrite; int64_t num; unsigned nread; uint64_t storedPaxosID, storedCommandID, expiryTime; ByteString userValue; isWrite = op->IsWrite(); if (isWrite && !transaction.IsActive()) { transaction.Set(table); transaction.Begin(); } op->status = true; if (op->IsWrite() && writePaxosID) { if (table->Set(&transaction, "@@paxosID", "1")) writePaxosID = false; } if (op->IsGet()) { op->value.Allocate(KEYSPACE_VAL_SIZE); op->status &= table->Get(NULL, op->key, vdata); if (op->status) { ReadValue(vdata, storedPaxosID, storedCommandID, userValue); op->value.Set(userValue); } op->service->OnComplete(op); } else if (op->IsList() || op->IsCount()) { AsyncListVisitor *alv = new AsyncListVisitor(op); MultiDatabaseOp* mdbop = new AsyncMultiDatabaseOp(); mdbop->Visit(table, *alv); dbReader.Add(mdbop); } else if (op->type == KeyspaceOp::SET) { WriteValue(vdata, 1, 0, op->value); op->status &= table->Set(&transaction, op->key, vdata); op->service->OnComplete(op); } else if (op->type == KeyspaceOp::TEST_AND_SET) { op->status &= table->Get(&transaction, op->key, vdata); if (op->status) { ReadValue(vdata, storedPaxosID, storedCommandID, userValue); if (userValue == op->test) { WriteValue(vdata, 1, 0, op->value); op->status &= table->Set(&transaction, op->key, vdata); } else op->value.Set(userValue); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::ADD) { // read number: op->status = table->Get(&transaction, op->key, vdata); if (op->status) { ReadValue(vdata, storedPaxosID, storedCommandID, userValue); // parse number: num = strntoint64(userValue.buffer, userValue.length, &nread); if (nread == (unsigned) userValue.length) { num = num + op->num; // print number: vdata.length = snwritef(vdata.buffer, vdata.size, "1:0:%I", num); // write number: op->status &= table->Set(&transaction, op->key, vdata); // returned to the user: vdata.length = snwritef(vdata.buffer, vdata.size, "%I", num); op->value.Allocate(vdata.length); op->value.Set(vdata); } else op->status = false; } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::RENAME) { op->status &= table->Get(&transaction, op->key, vdata); if (op->status) { // value doesn't change op->status &= table->Set(&transaction, op->newKey, vdata); if (op->status) op->status &= table->Delete(&transaction, op->key); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::DELETE) { op->status &= table->Delete(&transaction, op->key); op->service->OnComplete(op); } else if (op->type == KeyspaceOp::REMOVE) { op->value.Allocate(KEYSPACE_VAL_SIZE); op->status &= table->Get(&transaction, op->key, vdata); if (op->status) { ReadValue(vdata, storedPaxosID, storedCommandID, userValue); op->value.Set(userValue); op->status &= table->Delete(&transaction, op->key); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::PRUNE) { op->status &= table->Prune(&transaction, op->prefix); op->service->OnComplete(op); } else if (op->type == KeyspaceOp::SET_EXPIRY) { Log_Trace("Setting expiry for key: %.*s", op->key.length, op->key.buffer); // check old expiry WriteExpiryKey(kdata, op->key); if (table->Get(&transaction, kdata, vdata)) { // this key already had an expiry expiryTime = strntouint64(vdata.buffer, vdata.length, &nread); if (nread < 1) ASSERT_FAIL(); // delete old value WriteExpiryTime(kdata, expiryTime, op->key); table->Delete(&transaction, kdata); } // write !!t:<expirytime>:<key> => NULL WriteExpiryTime(kdata, op->nextExpiryTime, op->key); op->value.Clear(); table->Set(&transaction, kdata, op->value); // write !!k:<key> => <expiryTime> WriteExpiryKey(kdata, op->key); table->Set(&transaction, kdata, op->nextExpiryTime); InitExpiryTimer(); op->status = true; op->service->OnComplete(op); } else if (op->type == KeyspaceOp::REMOVE_EXPIRY) { Log_Trace("Removing expiry for key: %.*s", op->key.length, op->key.buffer); // check old expiry WriteExpiryKey(kdata, op->key); if (table->Get(&transaction, kdata, vdata)) { // this key already had an expiry expiryTime = strntouint64(vdata.buffer, vdata.length, &nread); if (nread < 1) ASSERT_FAIL(); // delete old value WriteExpiryTime(kdata, expiryTime, op->key); table->Delete(&transaction, kdata); } WriteExpiryKey(kdata, op->key); table->Delete(&transaction, kdata); InitExpiryTimer(); op->status = true; op->service->OnComplete(op); } else if (op->type == KeyspaceOp::CLEAR_EXPIRIES) { Log_Trace("Clearing all expiries"); kdata.Writef("!!"); table->Prune(&transaction, kdata, true); InitExpiryTimer(); op->status = true; op->service->OnComplete(op); } else ASSERT_FAIL(); return true; }
bool ReplicatedKeyspaceDB::Add(KeyspaceOp* op) { uint64_t storedPaxosID, storedCommandID; ByteString userValue; // don't allow writes for @@ keys if (op->IsWrite() && op->key.length > 2 && op->key.buffer[0] == '@' && op->key.buffer[1] == '@') return false; // don't allow writes for !! keys if (op->IsWrite() && op->key.length > 2 && op->key.buffer[0] == '!' && op->key.buffer[1] == '!') return false; if (catchingUp) return false; // reads are handled locally, they don't have to // be added to the ReplicatedLog if (op->IsGet()) { // only handle GETs if I'm the master and // it's safe to do so (I have NOPed) if (op->type == KeyspaceOp::GET && (!RLOG->IsMaster() || !RLOG->IsSafeDB())) return false; op->value.Allocate(KEYSPACE_VAL_SIZE); op->status = table->Get(NULL, op->key, rdata); if (op->status) { ReadValue(rdata, storedPaxosID, storedCommandID, userValue); op->value.Set(userValue); } op->service->OnComplete(op); return true; } if (op->IsList() || op->IsCount()) { if ((op->type == KeyspaceOp::LIST || op->type == KeyspaceOp::LISTP || op->type == KeyspaceOp::COUNT) && (!RLOG->IsMaster() || !RLOG->IsSafeDB())) return false; AsyncListVisitor *alv = new AsyncListVisitor(op); MultiDatabaseOp* mdbop = new AsyncMultiDatabaseOp(); mdbop->Visit(table, *alv); dbReader.Add(mdbop); return true; } // only handle writes if I'm the master if (!RLOG->IsMaster()) return false; if (op->IsExpiry()) expiryAdded = true; ops.Append(op); // TODO: huge hack if (estimatedLength < PAXOS_SIZE) { tmp.FromKeyspaceOp(op); if (tmp.Write(tmpBuffer)) estimatedLength += tmpBuffer.length; } if (estimatedLength >= PAXOS_SIZE) Submit(); return true; }
bool SingleKeyspaceDB::Add(KeyspaceOp* op) { // Log_Trace(); bool isWrite; int64_t num; unsigned nread; uint64_t storedPaxosID; uint64_t storedCommandID; ByteString userValue; isWrite = op->IsWrite(); if (isWrite && !transaction.IsActive()) { transaction.Set(table); transaction.Begin(); } op->status = true; if (op->IsWrite() && writePaxosID) { if (table->Set(&transaction, "@@paxosID", "1")) writePaxosID = false; } if (op->IsGet()) { op->value.Allocate(KEYSPACE_VAL_SIZE); op->status &= table->Get(NULL, op->key, data); if (op->status) { ReadValue(data, storedPaxosID, storedCommandID, userValue); op->value.Set(userValue); } op->service->OnComplete(op); } else if (op->IsList() || op->IsCount()) { AsyncListVisitor *alv = new AsyncListVisitor(op); MultiDatabaseOp* mdbop = new AsyncMultiDatabaseOp(); mdbop->Visit(table, *alv); dbReader.Add(mdbop); } else if (op->type == KeyspaceOp::SET) { WriteValue(data, 1, 0, op->value); op->status &= table->Set(&transaction, op->key, data); op->service->OnComplete(op); } else if (op->type == KeyspaceOp::TEST_AND_SET) { op->status &= table->Get(&transaction, op->key, data); if (op->status) { ReadValue(data, storedPaxosID, storedCommandID, userValue); if (userValue == op->test) { WriteValue(data, 1, 0, op->value); op->status &= table->Set(&transaction, op->key, data); } else op->value.Set(userValue); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::ADD) { // read number: op->status = table->Get(&transaction, op->key, data); if (op->status) { ReadValue(data, storedPaxosID, storedCommandID, userValue); // parse number: num = strntoint64(userValue.buffer, userValue.length, &nread); if (nread == (unsigned) userValue.length) { num = num + op->num; // print number: data.length = snwritef(data.buffer, data.size, "1:0:%I", num); // write number: op->status &= table->Set(&transaction, op->key, data); // returned to the user: data.length = snwritef(data.buffer, data.size, "%I", num); op->value.Allocate(data.length); op->value.Set(data); } else op->status = false; } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::RENAME) { op->status &= table->Get(&transaction, op->key, data); if (op->status) { // value doesn't change op->status &= table->Set(&transaction, op->newKey, data); if (op->status) op->status &= table->Delete(&transaction, op->key); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::DELETE) { op->status &= table->Delete(&transaction, op->key); op->service->OnComplete(op); } else if (op->type == KeyspaceOp::REMOVE) { op->value.Allocate(KEYSPACE_VAL_SIZE); op->status &= table->Get(&transaction, op->key, data); if (op->status) { ReadValue(data, storedPaxosID, storedCommandID, userValue); op->value.Set(userValue); op->status &= table->Delete(&transaction, op->key); } op->service->OnComplete(op); } else if (op->type == KeyspaceOp::PRUNE) { op->status &= table->Prune(&transaction, op->prefix); op->service->OnComplete(op); } else ASSERT_FAIL(); return true; }