blob: 44c42a0ac8479bfd85e0d91c73838fb7115c12cc [file]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "pegasus_server_test_base.h"
#include "message_utils.h"
#include "server/pegasus_server_write.h"
#include "server/pegasus_write_service_impl.h"
#include "base/pegasus_key_schema.h"
#include <dsn/utility/fail_point.h>
#include <dsn/utility/defer.h>
namespace pegasus {
namespace server {
class pegasus_server_write_test : public pegasus_server_test_base
{
std::unique_ptr<pegasus_server_write> _server_write;
public:
pegasus_server_write_test() : pegasus_server_test_base()
{
start();
_server_write = dsn::make_unique<pegasus_server_write>(_server.get(), true);
}
void test_batch_writes()
{
dsn::fail::setup();
dsn::fail::cfg("db_write_batch_put", "10%return()");
dsn::fail::cfg("db_write_batch_remove", "10%return()");
dsn::fail::cfg("db_write", "10%return()");
for (int decree = 1; decree <= 1000; decree++) {
RPC_MOCKING(put_rpc) RPC_MOCKING(remove_rpc)
{
dsn::blob key;
pegasus_generate_key(key, std::string("hash"), std::string("sort"));
dsn::apps::update_request req;
req.key = key;
req.value.assign("value", 0, 5);
int put_rpc_cnt = dsn::rand::next_u32(1, 10);
int remove_rpc_cnt = dsn::rand::next_u32(1, 10);
int total_rpc_cnt = put_rpc_cnt + remove_rpc_cnt;
/**
* writes[0] ~ writes[total_rpc_cnt-1] will be released by their corresponding
* rpc_holders, which created in on_batched_write_requests. So we don't need to
* release them here
**/
dsn::message_ex *writes[total_rpc_cnt];
for (int i = 0; i < put_rpc_cnt; i++) {
writes[i] = pegasus::create_put_request(req);
}
for (int i = put_rpc_cnt; i < total_rpc_cnt; i++) {
writes[i] = pegasus::create_remove_request(key);
}
int err =
_server_write->on_batched_write_requests(writes, total_rpc_cnt, decree, 0);
switch (err) {
case FAIL_DB_WRITE_BATCH_PUT:
case FAIL_DB_WRITE_BATCH_DELETE:
case FAIL_DB_WRITE:
case 0:
break;
default:
ASSERT_TRUE(false) << "unacceptable error: " << err;
}
// make sure everything is cleanup after batch write.
ASSERT_TRUE(_server_write->_put_rpc_batch.empty());
ASSERT_TRUE(_server_write->_remove_rpc_batch.empty());
ASSERT_TRUE(_server_write->_write_svc->_batch_qps_perfcounters.empty());
ASSERT_TRUE(_server_write->_write_svc->_batch_latency_perfcounters.empty());
ASSERT_EQ(_server_write->_write_svc->_batch_start_time, 0);
ASSERT_EQ(_server_write->_write_svc->_impl->_rocksdb_wrapper->_write_batch->Count(),
0);
ASSERT_EQ(_server_write->_write_svc->_impl->_update_responses.size(), 0);
ASSERT_EQ(put_rpc::mail_box().size(), put_rpc_cnt);
ASSERT_EQ(remove_rpc::mail_box().size(), remove_rpc_cnt);
for (auto &rpc : put_rpc::mail_box()) {
verify_response(rpc.response(), err, decree);
}
for (auto &rpc : remove_rpc::mail_box()) {
verify_response(rpc.response(), err, decree);
}
}
}
dsn::fail::teardown();
}
void verify_response(const dsn::apps::update_response &response, int err, int64_t decree)
{
ASSERT_EQ(response.error, err);
ASSERT_EQ(response.app_id, _gpid.get_app_id());
ASSERT_EQ(response.partition_index, _gpid.get_partition_index());
ASSERT_EQ(response.decree, decree);
ASSERT_EQ(response.server, _server_write->_write_svc->_impl->_primary_address);
}
};
TEST_F(pegasus_server_write_test, batch_writes) { test_batch_writes(); }
} // namespace server
} // namespace pegasus