blob: 4ab2834317712d2853f763637a649ed01efece60 [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.
*/
#ifndef _IGNITE_IMPL_THIN_DATA_ROUTER
#define _IGNITE_IMPL_THIN_DATA_ROUTER
#include <stdint.h>
#include <map>
#include <set>
#include <vector>
#include <memory>
#include <string>
#include <ignite/thin/ignite_client_configuration.h>
#include <ignite/common/concurrent.h>
#include <ignite/network/end_point.h>
#include <ignite/network/tcp_range.h>
#include <ignite/impl/binary/binary_writer_impl.h>
#include "impl/affinity/affinity_assignment.h"
#include "impl/affinity/affinity_manager.h"
#include "impl/data_channel.h"
namespace ignite
{
namespace impl
{
namespace thin
{
// Forward declaration.
class WritableKey;
/**
* Data router.
*
* Ensures there is a connection between client and one of the servers
* and routes data between them.
*/
class DataRouter
{
typedef std::map<Guid, SP_DataChannel> ChannelsGuidMap;
typedef std::vector<SP_DataChannel> ChannelsVector;
public:
/** Connection establishment timeout in seconds. */
enum { DEFAULT_CONNECT_TIMEOUT = 5 };
/** Network IO operation timeout in seconds. */
enum { DEFAULT_IO_TIMEOUT = 5 };
/** Default port. */
enum { DEFAULT_PORT = 10800 };
/**
* Constructor.
*
* @param cfg Configuration.
*/
DataRouter(const ignite::thin::IgniteClientConfiguration& cfg);
/**
* Destructor.
*/
~DataRouter();
/**
* Establish connection to cluster.
*/
void Connect();
/**
* Close connection.
*/
void Close();
/**
* Update affinity if needed.
*
* @param rsp Response.
*/
template <typename RspT>
void CheckAffinity(RspT& rsp)
{
const AffinityTopologyVersion* ver = rsp.GetAffinityTopologyVersion();
if (ver != 0 && config.IsAffinityAwareness())
affinityManager.UpdateAffinity(*ver);
}
/**
* Process meta if needed.
*
* @param metaVer Version of meta.
*/
void ProcessMeta(int32_t metaVer);
/**
* Synchronously send request message and receive response.
* Uses provided timeout.
*
* @param req Request message.
* @param rsp Response message.
* @throw IgniteError on error.
*/
template<typename ReqT, typename RspT>
void SyncMessage(const ReqT& req, RspT& rsp)
{
SP_DataChannel channel = GetRandomChannel();
int32_t metaVer = typeMgr.GetVersion();
SyncMessagePreferredChannelNoMetaUpdate(req, rsp, channel);
ProcessMeta(metaVer);
}
/**
* Synchronously send request message and receive response.
*
* @param req Request message.
* @param rsp Response message.
* @param hint Preferred server node to use.
* @throw IgniteError on error.
*/
template<typename ReqT, typename RspT>
void SyncMessage(const ReqT& req, RspT& rsp, const Guid& hint)
{
SP_DataChannel channel = GetBestChannel(hint);
int32_t metaVer = typeMgr.GetVersion();
SyncMessagePreferredChannelNoMetaUpdate(req, rsp, channel);
ProcessMeta(metaVer);
}
/**
* Synchronously send request message and receive response.
* Does not update metadata.
* Uses provided timeout.
*
* @param req Request message.
* @param rsp Response message.
* @throw IgniteError on error.
*/
template<typename ReqT, typename RspT>
void SyncMessageNoMetaUpdate(const ReqT& req, RspT& rsp)
{
SP_DataChannel channel = GetRandomChannel();
SyncMessagePreferredChannelNoMetaUpdate(req, rsp, channel);
}
/**
* Update affinity mapping for the cache.
*
* @param cacheId Cache ID.
*/
void RefreshAffinityMapping(int32_t cacheId);
/**
* Update affinity mapping for caches.
*
* @param cacheIds Cache IDs.
*/
void RefreshAffinityMapping(const std::vector<int32_t>& cacheIds);
/**
* Checked whether affinity awareness enabled.
*
* @return @c true if affinity awareness enabled.
*/
bool IsAffinityAwarenessEnabled() const
{
return config.IsAffinityAwareness();
}
/**
* Get affinity mapping for the cache.
*
* @param cacheId Cache ID.
* @return Mapping.
*/
affinity::SP_AffinityAssignment GetAffinityAssignment(int32_t cacheId) const;
private:
IGNITE_NO_COPY_ASSIGNMENT(DataRouter);
/**
* Invalidate provided data channel.
*
* @param channel Data channel.
*/
void InvalidateChannel(SP_DataChannel& channel);
/**
* Synchronously send request message and receive response.
*
* @param req Request message.
* @param rsp Response message.
* @param preferred Preferred channel to use.
* @throw IgniteError on error.
*/
template<typename ReqT, typename RspT>
void SyncMessagePreferredChannelNoMetaUpdate(const ReqT& req, RspT& rsp, const SP_DataChannel& preferred)
{
SP_DataChannel channel = preferred;
if (!channel.IsValid())
channel = GetRandomChannel();
if (!channel.IsValid())
{
throw IgniteError(IgniteError::IGNITE_ERR_NETWORK_FAILURE,
"Can not connect to any available cluster node. Please restart client");
}
try
{
channel.Get()->SyncMessage(req, rsp, ioTimeout);
}
catch (IgniteError&)
{
InvalidateChannel(channel);
}
if (!channel.IsValid())
{
throw IgniteError(IgniteError::IGNITE_ERR_NETWORK_FAILURE,
"Connection failure during command processing. Please re-run command");
}
CheckAffinity(rsp);
}
/** Shared pointer to end points. */
typedef common::concurrent::SharedPointer<network::EndPoints> SP_EndPoints;
/**
* Get random data channel.
*
* @return Random data channel or null, if not connected.
*/
SP_DataChannel GetRandomChannel();
/**
* Get random data channel.
* @warning May only be called when lock is held!
*
* @return Random data channel or null, if not connected.
*/
SP_DataChannel GetRandomChannelUnsafe();
/**
* Check whether the provided end point is provided by user using configuration.
*
* @param endPoint End point to check.
* @return @c true if provided by user using configuration.
*/
bool IsProvidedByUser(const network::EndPoint& endPoint);
/**
* Get the best data channel.
*
* @param hint GUID of preferred server node to use.
* @return The best available data channel or null if not connected.
*/
SP_DataChannel GetBestChannel(const Guid& hint);
/**
* Collect all addresses from string.
*
* @param str String with connection strings to parse.
* @param ranges Address ranges.
*/
static void CollectAddresses(const std::string& str, std::vector<network::TcpRange>& ranges);
/** IO timeout in seconds. */
int32_t ioTimeout;
/** Connection timeout in seconds. */
int32_t connectionTimeout;
/** Configuration. */
ignite::thin::IgniteClientConfiguration config;
/** Address ranges. */
std::vector<network::TcpRange> ranges;
/** Type updater. */
std::auto_ptr<binary::BinaryTypeUpdater> typeUpdater;
/** Metadata manager. */
binary::BinaryTypeManager typeMgr;
/** Data channels. */
ChannelsGuidMap channels;
/** Data channels. */
ChannelsVector legacyChannels;
/** Channels mutex. */
common::concurrent::CriticalSection channelsMutex;
/** Cache affinity manager. */
affinity::AffinityManager affinityManager;
};
/** Shared pointer type. */
typedef common::concurrent::SharedPointer<DataRouter> SP_DataRouter;
}
}
}
#endif //_IGNITE_IMPL_THIN_DATA_ROUTER