blob: 5f00146f6784c7c591b109f3c621d74e8b9a54ef [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 <dsn/tool-api/task_spec.h>
#include <rrdb/rrdb.code.definition.h>
#include "proxy_layer.h"
namespace pegasus {
namespace proxy {
proxy_stub::proxy_stub(const proxy_session::factory &f,
const char *cluster,
const char *app,
const char *geo_app)
: serverlet<proxy_stub>("proxy_stub"),
_factory(f),
_cluster(cluster),
_app(app),
_geo_app(geo_app)
{
dsn::task_spec::get(RPC_CALL_RAW_MESSAGE)->allow_inline = true;
dsn::task_spec::get(RPC_CALL_RAW_SESSION_DISCONNECT)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_PUT_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_MULTI_PUT_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_REMOVE_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_MULTI_REMOVE_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_GET_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_MULTI_GET_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_SORTKEY_COUNT_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_TTL_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_GET_SCANNER_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_SCAN_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_CLEAR_SCANNER_ACK)->allow_inline = true;
dsn::task_spec::get(dsn::apps::RPC_RRDB_RRDB_INCR_ACK)->allow_inline = true;
open_service();
}
void proxy_stub::on_rpc_request(dsn::message_ex *request)
{
::dsn::rpc_address source = request->header->from_address;
std::shared_ptr<proxy_session> session;
{
::dsn::zauto_read_lock l(_lock);
auto it = _sessions.find(source);
if (it != _sessions.end()) {
session = it->second;
}
}
if (nullptr == session) {
::dsn::zauto_write_lock l(_lock);
auto it = _sessions.find(source);
if (it != _sessions.end()) {
session = it->second;
} else {
session = _factory(this, request);
_sessions.emplace(source, session);
}
}
session->on_recv_request(request);
}
void proxy_stub::on_recv_remove_session_request(dsn::message_ex *request)
{
::dsn::rpc_address source = request->header->from_address;
remove_session(source);
}
void proxy_stub::remove_session(dsn::rpc_address remote_address)
{
std::shared_ptr<proxy_session> session;
{
::dsn::zauto_write_lock l(_lock);
auto iter = _sessions.find(remote_address);
if (iter == _sessions.end()) {
dwarn("%s has been removed from proxy stub", remote_address.to_string());
return;
}
ddebug("remove %s from proxy stub", remote_address.to_string());
session = std::move(iter->second);
_sessions.erase(iter);
}
session->on_remove_session();
}
proxy_session::proxy_session(proxy_stub *op, dsn::message_ex *first_msg)
: _stub(op), _is_session_reset(false), _backup_one_request(first_msg)
{
dassert(first_msg != nullptr, "null msg when create session");
_backup_one_request->add_ref();
_remote_address = _backup_one_request->header->from_address;
dassert(_remote_address.type() == HOST_TYPE_IPV4,
"invalid rpc_address type, type = %d",
(int)_remote_address.type());
}
proxy_session::~proxy_session()
{
_backup_one_request->release_ref();
ddebug("proxy session %s destroyed", _remote_address.to_string());
}
void proxy_session::on_recv_request(dsn::message_ex *msg)
{
// NOTICE:
// 1. in the implementation of "parse", the msg may add_ref & release_ref.
// so if the ref_count of msg is 0 before call "parse", the msg may be released already
// after "parse" returns. so please take care when you want to
// use "msg" after call "parse"
//
// 2. as "on_recv_request" won't be called concurrently, it's not necessary to call
// "parse" with a lock. a subclass may implement a lock inside parse if necessary
if (!parse(msg)) {
derror("%s: got invalid message, try to remove proxy session from proxy stub",
_remote_address.to_string());
_stub->remove_session(_remote_address);
derror("close the rpc session %s", _remote_address.to_string());
((dsn::message_ex *)_backup_one_request)->io_session->close();
}
}
void proxy_session::on_remove_session() { _is_session_reset.store(true); }
dsn::message_ex *proxy_session::create_response() { return _backup_one_request->create_response(); }
} // namespace proxy
} // namespace pegasus