Example #1
0
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;
}
Example #3
0
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;
}