<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file ddr_phy.H
/// @brief Subroutines to manipulate the phy, or used during phy procedures
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_DDR_PHY_H_
#define _MSS_DDR_PHY_H_

#include <fapi2.H>
#include <lib/mss_attribute_accessors.H>

namespace mss
{

///
/// @brief Perform initializations for the PHY
/// @param[in] i_target the MCBIST which has the PHYs to initialize
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode phy_scominit(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target);

///
/// @brief change resetn to the given state
/// @param[in] i_target the mcbist
/// @param[in] i_state the desired state
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode change_resetn( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target, states i_state );

///
/// @brief perform the zctl enable process
/// @param[in] i_target the mcbist for the reset recover
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode enable_zctl( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

/// @brief Change mclk low
/// @param[in] i_target mcbist target
/// @param[in] i_state mss::HIGH or mss::LOW - desired state.
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode change_force_mclk_low (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
        const mss::states i_state);
///
/// @brief Unset the PLL and check to see that the PLL's have started
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode deassert_pll_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Change the continuous update mode of the PR CNTL registers
/// @note Will take the SYSCLK control out of reset, too
/// @param[in] i_target the mcbist target
/// @param[in] i_state, mss::ON if you want to be in continuous mode, mss::OFF to turn it off
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
        const states i_state );

///
/// @brief Deassetr the sys clk reset
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode deassert_sysclk_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Reset the training delay configureation
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode reset_delay_values( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Check if the bang bang lock has succeeded
/// @param[in] i_target a MCBIST target
/// @return FAPI2_RC_SUCCESs iff ok
///
fapi2::ReturnCode check_bang_bang_lock( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Configure the DP16 sysclk
/// @param[in] i_target a MCBIST target
/// @return FAPI2_RC_SUCCESs iff ok
///
fapi2::ReturnCode setup_dp16_sysclk( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief check and process initial cal errors
/// @tparam T the type of the target in question
/// @param[in] i_target the port in question
/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff no error
///
template< fapi2::TargetType T >
fapi2::ReturnCode process_initial_cal_errors( const fapi2::Target<T>& i_target );

///
/// @brief Setup all the cal config register
/// @tparam T, the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @param[in] i_rank_pairs the vector of currently configured rank pairs
/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode setup_cal_config( const fapi2::Target<T>& i_target,
                                    const std::vector<uint64_t> i_rank_pairs,
                                    const fapi2::buffer<uint16_t> i_cal_steps_enabled);

///
/// @brief Setup all the cal config register
/// @param[in] i_target the target associated with this cal setup
/// @param[in] i_rank one currently configured rank pairs
/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
                                    const uint64_t i_rank,
                                    const fapi2::buffer<uint16_t> i_cal_steps_enabled);

///
/// @brief Setup seq_config0
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_seq_config0( const fapi2::Target<T>& i_target );

///
/// @brief Setup seq_config0
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_config0( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup odt_wr/rd_config
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_odt_config( const fapi2::Target<T>& i_target );

///
/// @brief Setup odt_wr/rd_config
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<T>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Perform the DLL calibration
/// @tparam T the target type of the MCBIST
/// @param[in] i_target the target associated with this DLL cal
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode dll_calibration( const fapi2::Target<T>& i_target );

///
/// @brief Perform the DLL calibration
/// @param[in] i_target the target associated with this DLL cal
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Flush the output drivers
/// @tparam T the target type of the MCBIST
/// @param[in] i_target the target associated with the phy reset sequence
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode flush_output_drivers( const fapi2::Target<T>& i_target );

///
/// @brief Flush the output drivers
/// @param[in] i_target the target associated with the phy reset sequence
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode flush_output_drivers( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup the PC CONFIG0 register
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
fapi2::ReturnCode set_pc_config0(const fapi2::Target<T>& i_target);

///
/// @brief Setup the PC CONFIG1 register
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
fapi2::ReturnCode set_pc_config1(const fapi2::Target<T>& i_target);

///
/// @brief Return the DIMM target for the primary rank in the specificed rank pair
/// @tparam T fapi2::TargetType of the port target
/// @param[in] i_target the target
/// @param[in] i_rp the rank pair
/// @param[out] fapi2::Target<fapi2::TARGET_TYPE_DIMM>
/// @return FAPI2_RC_SUCCESS iff ok
///
template<fapi2::TargetType T>
fapi2::ReturnCode rank_pair_primary_to_dimm(const fapi2::Target<T>& i_target, const uint64_t i_rp,
        fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm);

}
#endif
<commit_msg>Added support for PHY drive strength attributes<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/lib/phy/ddr_phy.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file ddr_phy.H
/// @brief Subroutines to manipulate the phy, or used during phy procedures
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 2
// *HWP Consumed by: FSP:HB

#ifndef _MSS_DDR_PHY_H_
#define _MSS_DDR_PHY_H_

#include <fapi2.H>
#include <lib/mss_attribute_accessors.H>

namespace mss
{

///
/// @brief Perform initializations for the PHY
/// @param[in] i_target the MCBIST which has the PHYs to initialize
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode phy_scominit(const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target);

///
/// @brief change resetn to the given state
/// @param[in] i_target the mcbist
/// @param[in] i_state the desired state
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode change_resetn( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target, states i_state );

///
/// @brief perform the zctl enable process
/// @param[in] i_target the mcbist for the reset recover
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode enable_zctl( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

/// @brief Change mclk low
/// @param[in] i_target mcbist target
/// @param[in] i_state mss::HIGH or mss::LOW - desired state.
/// @return FAPI2_RC_SUCCESS iff ok
///
fapi2::ReturnCode change_force_mclk_low (const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
        const mss::states i_state);
///
/// @brief Unset the PLL and check to see that the PLL's have started
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode deassert_pll_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Change the continuous update mode of the PR CNTL registers
/// @note Will take the SYSCLK control out of reset, too
/// @param[in] i_target the mcbist target
/// @param[in] i_state, mss::ON if you want to be in continuous mode, mss::OFF to turn it off
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode setup_phase_rotator_control_registers( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target,
        const states i_state );

///
/// @brief Deassetr the sys clk reset
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode deassert_sysclk_reset( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Reset the training delay configureation
/// @param[in] i_target the mcbist target
/// @return FAPI2_RC_SUCCES iff ok
///
fapi2::ReturnCode reset_delay_values( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Check if the bang bang lock has succeeded
/// @param[in] i_target a MCBIST target
/// @return FAPI2_RC_SUCCESs iff ok
///
fapi2::ReturnCode check_bang_bang_lock( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Configure the DP16 sysclk
/// @param[in] i_target a MCBIST target
/// @return FAPI2_RC_SUCCESs iff ok
///
fapi2::ReturnCode setup_dp16_sysclk( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief check and process initial cal errors
/// @tparam T the type of the target in question
/// @param[in] i_target the port in question
/// @return fapi2::ReturnCode, FAPI2_RC_SUCCESS iff no error
///
template< fapi2::TargetType T >
fapi2::ReturnCode process_initial_cal_errors( const fapi2::Target<T>& i_target );

///
/// @brief Setup all the cal config register
/// @tparam T, the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @param[in] i_rank_pairs the vector of currently configured rank pairs
/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode setup_cal_config( const fapi2::Target<T>& i_target,
                                    const std::vector<uint64_t> i_rank_pairs,
                                    const fapi2::buffer<uint16_t> i_cal_steps_enabled);

///
/// @brief Setup all the cal config register
/// @param[in] i_target the target associated with this cal setup
/// @param[in] i_rank one currently configured rank pairs
/// @param[in] i_cal_steps_enabled fapi2::buffer<uint16_t> representing the cal steps to enable
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
fapi2::ReturnCode setup_cal_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target,
                                    const uint64_t i_rank,
                                    const fapi2::buffer<uint16_t> i_cal_steps_enabled);

///
/// @brief Setup seq_config0
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_seq_config0( const fapi2::Target<T>& i_target );

///
/// @brief Setup seq_config0
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_config0( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup odt_wr/rd_config
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_odt_config( const fapi2::Target<T>& i_target );

///
/// @brief Setup odt_wr/rd_config
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_odt_config( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @tparam T the target type of the MCA/MBA
/// @param[in] i_target the target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<T>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Perform the DLL calibration
/// @tparam T the target type of the MCBIST
/// @param[in] i_target the target associated with this DLL cal
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode dll_calibration( const fapi2::Target<T>& i_target );

///
/// @brief Perform the DLL calibration
/// @param[in] i_target the target associated with this DLL cal
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode dll_calibration( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Flush the output drivers
/// @tparam T the target type of the MCBIST
/// @param[in] i_target the target associated with the phy reset sequence
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template< fapi2::TargetType T >
fapi2::ReturnCode flush_output_drivers( const fapi2::Target<T>& i_target );

///
/// @brief Flush the output drivers
/// @param[in] i_target the target associated with the phy reset sequence
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode flush_output_drivers( const fapi2::Target<fapi2::TARGET_TYPE_MCBIST>& i_target );

///
/// @brief Setup seq_rd_wr_data
/// @param[in] i_target the MCA target associated with this cal setup
/// @return FAPI2_RC_SUCCESS iff setup was successful
///
template<>
fapi2::ReturnCode reset_seq_rd_wr_data( const fapi2::Target<fapi2::TARGET_TYPE_MCA>& i_target );

///
/// @brief Setup the PC CONFIG0 register
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
fapi2::ReturnCode set_pc_config0(const fapi2::Target<T>& i_target);

///
/// @brief Setup the PC CONFIG1 register
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
fapi2::ReturnCode set_pc_config1(const fapi2::Target<T>& i_target);

///
/// @brief Return the DIMM target for the primary rank in the specificed rank pair
/// @tparam T fapi2::TargetType of the port target
/// @param[in] i_target the target
/// @param[in] i_rp the rank pair
/// @param[out] fapi2::Target<fapi2::TARGET_TYPE_DIMM>
/// @return FAPI2_RC_SUCCESS iff ok
///
template<fapi2::TargetType T>
fapi2::ReturnCode rank_pair_primary_to_dimm(const fapi2::Target<T>& i_target, const uint64_t i_rp,
        fapi2::Target<fapi2::TARGET_TYPE_DIMM>& o_dimm);

///
/// @brief Sets up the IO impedances (ADR DRV's and DP DRV's/RCV's)
/// @tparam T the fapi2::TargetType
/// @param[in] i_target the target (MCA/MCBIST or MBA?)
/// @return FAPI2_RC_SUCCESS if and only if ok
///
template< fapi2::TargetType T>
fapi2::ReturnCode reset_io_impedances(const fapi2::Target<T>& i_target);

}
#endif
<|endoftext|>


<commit_before>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const std::string &socket_path) :
    AbstractServerConnector(),
    socket_path(socket_path.substr(0, PATH_MAX)),
    running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
    if(!this->running)
    {
        //Create and bind socket here.
    	//Then launch the listenning loop.
    	this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		//cout << "(" << pthread_self() << ") " << "Will launch the thread for the loop" << endl;
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
    }
    //cout << "(" << pthread_self() << ") " << "Returning " << this->running << endl;
    return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
    if(this->running)
    {
       	close(this->socket_fd);
       	unlink(this->socket_path.c_str());
        this->running = false;
    }
    return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	//cout << "(" << pthread_self() << ") " << "Entered in send response" << endl;
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	//cout << "(" << pthread_self() << ") " << "Will write response #" << response << "#";
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = response.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		write(connection_fd, toSend.c_str(), toSend.size());
 	}
	else {
		write(connection_fd, response.c_str(), response.size());
	}

	//cout << "(" << pthread_self() << ") " << "Will close client socket" << endl;
	close(connection_fd);
	return true;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length;
	//cout << "(" << pthread_self() << ") " << "Will launch the loop" << endl;
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		//cout << "(" << pthread_self() << ") " << "Client connected" << endl;
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		//cout << "(" << pthread_self() << ") " << "Will launch the thread to handle the request" << endl;
		//cout << "Sending instance=" << this << endl;
		//cout << "Sending connection_fd=" << connection_fd << endl;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	//cout << "(" << pthread_self() << ") " << "Entrered in generate response" << endl;
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	//cout << "Got instance=" << instance << endl;
	int connection_fd = params->connection_fd;
	//cout << "Got connection_fd=" << connection_fd << endl;
	//cout << "(" << pthread_self() << ") " << "Obtained params" << endl;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	//cout << "(" << pthread_self() << ") " << "Will read the request" << endl;
	string request;
	do { //The client sends its json formatted request and an \0.
		//cout << "(" << pthread_self() << ") " << "Current request state: #" << request << "#";
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		//cout << "(" << pthread_self() << ") " << "Received part of request: #" << buffer << "#";
		if(request.empty())
			request = string(buffer);
		else
			request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);

	//cout << "(" << pthread_self() << ") " << "Received request #" << request << "#" << endl;

	//cout << "(" << pthread_self() << ") " << "Will launch OnRequest" << endl;
	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}
<commit_msg>Corrected some buffer wrong reading/writing.<commit_after>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const std::string &socket_path) :
    AbstractServerConnector(),
    socket_path(socket_path.substr(0, PATH_MAX)),
    running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
    if(!this->running)
    {
        //Create and bind socket here.
    	//Then launch the listenning loop.
    	this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		//cout << "(" << pthread_self() << ") " << "Will launch the thread for the loop" << endl;
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
    }
    //cout << "(" << pthread_self() << ") " << "Returning " << this->running << endl;
    return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
    if(this->running)
    {
       	close(this->socket_fd);
       	unlink(this->socket_path.c_str());
        this->running = false;
    }
    return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	//cout << "(" << pthread_self() << ") " << "Entered in send response" << endl;
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	string temp = response;
	if(temp.find(DELIMITER_CHAR) == string::npos) {
		//cout << "Appending delimited char" << endl;
		temp.append(1, DELIMITER_CHAR);
		//cout << "Temp is #" << temp << "#" << endl;
	}
	//cout << "Sending #" << temp << "#" << endl;
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = temp.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		write(connection_fd, toSend.c_str(), toSend.size());
	}
	else {
		write(connection_fd, temp.c_str(), temp.size());
	}
	//cout << "(" << pthread_self() << ") " << "Will close client socket" << endl;
	close(connection_fd);
	return true;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length;
	//cout << "(" << pthread_self() << ") " << "Will launch the loop" << endl;
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		//cout << "(" << pthread_self() << ") " << "Client connected" << endl;
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		//cout << "(" << pthread_self() << ") " << "Will launch the thread to handle the request" << endl;
		//cout << "Sending instance=" << this << endl;
		//cout << "Sending connection_fd=" << connection_fd << endl;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	//cout << "(" << pthread_self() << ") " << "Entrered in generate response" << endl;
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	//cout << "Got instance=" << instance << endl;
	int connection_fd = params->connection_fd;
	//cout << "Got connection_fd=" << connection_fd << endl;
	//cout << "(" << pthread_self() << ") " << "Obtained params" << endl;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	//cout << "(" << pthread_self() << ") " << "Will read the request" << endl;
	string request;
	do { //The client sends its json formatted request and a delimiter request.
		//cout << "(" << pthread_self() << ") " << "Current request state: #" << request << "#";
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		//cout << "(" << pthread_self() << ") " << "Received part of request: #" << buffer << "#";
		request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);

	//cout << "(" << pthread_self() << ") " << "Received request #" << request << "#" << endl;

	//cout << "(" << pthread_self() << ") " << "Will launch OnRequest" << endl;
	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include <stdio.h>
//#include "leveldb/expiry.h"
#include "db/dbformat.h"
#include "db/version_set.h"
#include "port/port.h"
#include "util/coding.h"

namespace leveldb {

static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
  assert(seq <= kMaxSequenceNumber);
  // assert(t <= kValueTypeForSeek);  requires revisit once expiry live
  assert(t <= kTypeValueExplicitExpiry);  // temp replacement for above
  return (seq << 8) | t;
}

void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
  result->append(key.user_key.data(), key.user_key.size());
  if (IsExpiryKey(key.type))
    PutFixed64(result, key.expiry);
  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
}

std::string ParsedInternalKey::DebugString() const {
  char buf[50];
  if (IsExpiryKey(type))
    snprintf(buf, sizeof(buf), "' @ %llu %llu : %d",
             (unsigned long long) expiry,
             (unsigned long long) sequence,
             int(type));
  else
    snprintf(buf, sizeof(buf), "' @ %llu : %d",
             (unsigned long long) sequence,
             int(type));
  std::string result = "'";
  result += HexString(user_key.ToString());
  result += buf;
  return result;
}

std::string ParsedInternalKey::DebugStringHex() const {
  char buf[50];
  if (IsExpiryKey(type))
    snprintf(buf, sizeof(buf), "' @ %llu %llu : %d",
             (unsigned long long) expiry,
             (unsigned long long) sequence,
             int(type));
  else
    snprintf(buf, sizeof(buf), "' @ %llu : %d",
             (unsigned long long) sequence,
             int(type));
  std::string result = "'";
  result += HexString(user_key);
  result += buf;
  return result;
}

std::string InternalKey::DebugString() const {
  std::string result;
  ParsedInternalKey parsed;
  if (ParseInternalKey(rep_, &parsed)) {
    result = parsed.DebugString();
  } else {
    result = "(bad)";
    result.append(EscapeString(rep_));
  }
  return result;
}

const char* InternalKeyComparator::Name() const {
  return "leveldb.InternalKeyComparator";
}

int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
  // Order by:
  //    increasing user key (according to user-supplied comparator)
  //    decreasing sequence number
  //    decreasing type (though sequence# should be enough to disambiguate)
  int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
  if (r == 0) {
    uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
    uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
    if (IsExpiryKey((ValueType)*(unsigned char *)&anum)) *(unsigned char*)&anum=(unsigned char)kTypeValue;
    if (IsExpiryKey((ValueType)*(unsigned char *)&bnum)) *(unsigned char*)&bnum=(unsigned char)kTypeValue;
    if (anum > bnum) {
      r = -1;
    } else if (anum < bnum) {
      r = +1;
    }
  }
  return r;
}

void InternalKeyComparator::FindShortestSeparator(
      std::string* start,
      const Slice& limit) const {
  // Attempt to shorten the user portion of the key
  Slice user_start = ExtractUserKey(*start);
  Slice user_limit = ExtractUserKey(limit);
  std::string tmp(user_start.data(), user_start.size());
  user_comparator_->FindShortestSeparator(&tmp, user_limit);
  if (tmp.size() < user_start.size() &&
      user_comparator_->Compare(user_start, tmp) < 0) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*start, tmp) < 0);
    assert(this->Compare(tmp, limit) < 0);
    start->swap(tmp);
  }
}

void InternalKeyComparator::FindShortSuccessor(std::string* key) const {
  Slice user_key = ExtractUserKey(*key);
  std::string tmp(user_key.data(), user_key.size());
  user_comparator_->FindShortSuccessor(&tmp);
  if (tmp.size() < user_key.size() &&
      user_comparator_->Compare(user_key, tmp) < 0) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*key, tmp) < 0);
    key->swap(tmp);
  }
}

const char* InternalFilterPolicy::Name() const {
  return user_policy_->Name();
}

void InternalFilterPolicy::CreateFilter(const Slice* keys, int n,
                                        std::string* dst) const {
  // We rely on the fact that the code in table.cc does not mind us
  // adjusting keys[].
  Slice* mkey = const_cast<Slice*>(keys);
  for (int i = 0; i < n; i++) {
    mkey[i] = ExtractUserKey(keys[i]);
    // TODO(sanjay): Suppress dups?
  }
  user_policy_->CreateFilter(keys, n, dst);
}

bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const {
  return user_policy_->KeyMayMatch(ExtractUserKey(key), f);
}

  LookupKey::LookupKey(const Slice& user_key, SequenceNumber s, KeyMetaData * meta) {
  meta_=meta;
  size_t usize = user_key.size();
  size_t needed = usize + 13;  // A conservative estimate
  char* dst;
  if (needed <= sizeof(space_)) {
    dst = space_;
  } else {
    dst = new char[needed];
  }
  start_ = dst;
  dst = EncodeVarint32(dst, usize + 8);
  kstart_ = dst;
  memcpy(dst, user_key.data(), usize);
  dst += usize;
  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
  dst += 8;
  end_ = dst;
}

KeyRetirement::KeyRetirement(
    const Comparator * Comparator,
    SequenceNumber SmallestSnapshot,
    const Options * Opts,
    Compaction * const Compaction)
    : has_current_user_key(false), last_sequence_for_key(kMaxSequenceNumber),
      user_comparator(Comparator), smallest_snapshot(SmallestSnapshot),
      options(Opts), compaction(Compaction),
      valid(false), dropped(0), expired(0)
{
    // NULL is ok for compaction
    valid=(NULL!=user_comparator);

    return;
}   // KeyRetirement::KeyRetirement

KeyRetirement::~KeyRetirement()
{
    if (0!=expired)
        gPerfCounters->Add(ePerfExpiredKeys, expired);
}   // KeyRetirement::~KeyRetirement

bool
KeyRetirement::operator()(
    Slice & key)
{
    ParsedInternalKey ikey;
    bool drop = false, expire_flag;

    if (valid)
    {
        if (!ParseInternalKey(key, &ikey))
        {
            // Do not hide error keys
            current_user_key.clear();
            has_current_user_key = false;
            last_sequence_for_key = kMaxSequenceNumber;
        }   // else
        else
        {
            if (!has_current_user_key ||
                user_comparator->Compare(ikey.user_key,
                                         Slice(current_user_key)) != 0)
            {
                // First occurrence of this user key
                current_user_key.assign(ikey.user_key.data(), ikey.user_key.size());
                has_current_user_key = true;
                last_sequence_for_key = kMaxSequenceNumber;
            }   // if

            if (last_sequence_for_key <= smallest_snapshot)
            {
                // Hidden by an newer entry for same user key
                drop = true;    // (A)
            }   // if

            else
            {
                if (NULL!=options && NULL!=options->expiry_module.get())
                    expire_flag=options->expiry_module->KeyRetirementCallback(ikey);

                if ((ikey.type == kTypeDeletion || expire_flag)
                    && ikey.sequence <= smallest_snapshot
                    && NULL!=compaction  // mem to level0 ignores this test
                    && compaction->IsBaseLevelForKey(ikey.user_key))
                {
                    // For this user key:
                    // (1) there is no data in higher levels
                    // (2) data in lower levels will have larger sequence numbers
                    // (3) data in layers that are being compacted here and have
                    //     smaller sequence numbers will be dropped in the next
                    //     few iterations of this loop (by rule (A) above).
                    // Therefore this deletion marker is obsolete and can be dropped.
                    drop = true;

                    if (expire_flag)
                        ++expired;
                    else
                        ++dropped;
                }   // if
            }   // else

            last_sequence_for_key = ikey.sequence;
        }   // else
    }   // if

#if 0
    // needs clean up to be used again
    Log(options_.info_log,
        "  Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, "
        "%d smallest_snapshot: %d",
        ikey.user_key.ToString().c_str(),
        (int)ikey.sequence, ikey.type, kTypeValue, drop,
        compact->compaction->IsBaseLevelForKey(ikey.user_key),
        (int)last_sequence_for_key, (int)compact->smallest_snapshot);
#endif
    return(drop);

}   // KeyRetirement::operator(Slice & )

}  // namespace leveldb
<commit_msg>duplicate check-in?<commit_after>// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. See the AUTHORS file for names of contributors.

#include <stdio.h>
//#include "leveldb/expiry.h"
#include "db/dbformat.h"
#include "db/version_set.h"
#include "port/port.h"
#include "util/coding.h"

namespace leveldb {

static uint64_t PackSequenceAndType(uint64_t seq, ValueType t) {
  assert(seq <= kMaxSequenceNumber);
  // assert(t <= kValueTypeForSeek);  requires revisit once expiry live
  assert(t <= kTypeValueExplicitExpiry);  // temp replacement for above
  return (seq << 8) | t;
}

void AppendInternalKey(std::string* result, const ParsedInternalKey& key) {
  result->append(key.user_key.data(), key.user_key.size());
  if (IsExpiryKey(key.type))
    PutFixed64(result, key.expiry);
  PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
}

std::string ParsedInternalKey::DebugString() const {
  char buf[50];
  if (IsExpiryKey(type))
    snprintf(buf, sizeof(buf), "' @ %llu %llu : %d",
             (unsigned long long) expiry,
             (unsigned long long) sequence,
             int(type));
  else
    snprintf(buf, sizeof(buf), "' @ %llu : %d",
             (unsigned long long) sequence,
             int(type));
  std::string result = "'";
  result += HexString(user_key.ToString());
  result += buf;
  return result;
}

std::string ParsedInternalKey::DebugStringHex() const {
  char buf[50];
  if (IsExpiryKey(type))
    snprintf(buf, sizeof(buf), "' @ %llu %llu : %d",
             (unsigned long long) expiry,
             (unsigned long long) sequence,
             int(type));
  else
    snprintf(buf, sizeof(buf), "' @ %llu : %d",
             (unsigned long long) sequence,
             int(type));
  std::string result = "'";
  result += HexString(user_key);
  result += buf;
  return result;
}

std::string InternalKey::DebugString() const {
  std::string result;
  ParsedInternalKey parsed;
  if (ParseInternalKey(rep_, &parsed)) {
    result = parsed.DebugString();
  } else {
    result = "(bad)";
    result.append(EscapeString(rep_));
  }
  return result;
}

const char* InternalKeyComparator::Name() const {
  return "leveldb.InternalKeyComparator";
}

int InternalKeyComparator::Compare(const Slice& akey, const Slice& bkey) const {
  // Order by:
  //    increasing user key (according to user-supplied comparator)
  //    decreasing sequence number
  //    decreasing type (though sequence# should be enough to disambiguate)
  int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
  if (r == 0) {
    uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
    uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
    if (IsExpiryKey((ValueType)*(unsigned char *)&anum)) *(unsigned char*)&anum=(unsigned char)kTypeValue;
    if (IsExpiryKey((ValueType)*(unsigned char *)&bnum)) *(unsigned char*)&bnum=(unsigned char)kTypeValue;
    if (anum > bnum) {
      r = -1;
    } else if (anum < bnum) {
      r = +1;
    }
  }
  return r;
}

void InternalKeyComparator::FindShortestSeparator(
      std::string* start,
      const Slice& limit) const {
  // Attempt to shorten the user portion of the key
  Slice user_start = ExtractUserKey(*start);
  Slice user_limit = ExtractUserKey(limit);
  std::string tmp(user_start.data(), user_start.size());
  user_comparator_->FindShortestSeparator(&tmp, user_limit);
  if (tmp.size() < user_start.size() &&
      user_comparator_->Compare(user_start, tmp) < 0) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*start, tmp) < 0);
    assert(this->Compare(tmp, limit) < 0);
    start->swap(tmp);
  }
}

void InternalKeyComparator::FindShortSuccessor(std::string* key) const {
  Slice user_key = ExtractUserKey(*key);
  std::string tmp(user_key.data(), user_key.size());
  user_comparator_->FindShortSuccessor(&tmp);
  if (tmp.size() < user_key.size() &&
      user_comparator_->Compare(user_key, tmp) < 0) {
    // User key has become shorter physically, but larger logically.
    // Tack on the earliest possible number to the shortened user key.
    PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber,kValueTypeForSeek));
    assert(this->Compare(*key, tmp) < 0);
    key->swap(tmp);
  }
}

const char* InternalFilterPolicy::Name() const {
  return user_policy_->Name();
}

void InternalFilterPolicy::CreateFilter(const Slice* keys, int n,
                                        std::string* dst) const {
  // We rely on the fact that the code in table.cc does not mind us
  // adjusting keys[].
  Slice* mkey = const_cast<Slice*>(keys);
  for (int i = 0; i < n; i++) {
    mkey[i] = ExtractUserKey(keys[i]);
    // TODO(sanjay): Suppress dups?
  }
  user_policy_->CreateFilter(keys, n, dst);
}

bool InternalFilterPolicy::KeyMayMatch(const Slice& key, const Slice& f) const {
  return user_policy_->KeyMayMatch(ExtractUserKey(key), f);
}

  LookupKey::LookupKey(const Slice& user_key, SequenceNumber s, KeyMetaData * meta) {
  meta_=meta;
  size_t usize = user_key.size();
  size_t needed = usize + 13;  // A conservative estimate
  char* dst;
  if (needed <= sizeof(space_)) {
    dst = space_;
  } else {
    dst = new char[needed];
  }
  start_ = dst;
  dst = EncodeVarint32(dst, usize + 8);
  kstart_ = dst;
  memcpy(dst, user_key.data(), usize);
  dst += usize;
  EncodeFixed64(dst, PackSequenceAndType(s, kValueTypeForSeek));
  dst += 8;
  end_ = dst;
}

KeyRetirement::KeyRetirement(
    const Comparator * Comparator,
    SequenceNumber SmallestSnapshot,
    const Options * Opts,
    Compaction * const Compaction)
    : has_current_user_key(false), last_sequence_for_key(kMaxSequenceNumber),
      user_comparator(Comparator), smallest_snapshot(SmallestSnapshot),
      options(Opts), compaction(Compaction),
      valid(false), dropped(0), expired(0)
{
    // NULL is ok for compaction
    valid=(NULL!=user_comparator);

    return;
}   // KeyRetirement::KeyRetirement

KeyRetirement::~KeyRetirement()
{
    if (0!=expired)
        gPerfCounters->Add(ePerfExpiredKeys, expired);
}   // KeyRetirement::~KeyRetirement

bool
KeyRetirement::operator()(
    Slice & key)
{
    ParsedInternalKey ikey;
    bool drop = false, expire_flag;

    if (valid)
    {
        if (!ParseInternalKey(key, &ikey))
        {
            // Do not hide error keys
            current_user_key.clear();
            has_current_user_key = false;
            last_sequence_for_key = kMaxSequenceNumber;
        }   // else
        else
        {
            if (!has_current_user_key ||
                user_comparator->Compare(ikey.user_key,
                                         Slice(current_user_key)) != 0)
            {
                // First occurrence of this user key
                current_user_key.assign(ikey.user_key.data(), ikey.user_key.size());
                has_current_user_key = true;
                last_sequence_for_key = kMaxSequenceNumber;
            }   // if

            if (last_sequence_for_key <= smallest_snapshot)
            {
                // Hidden by an newer entry for same user key
                drop = true;    // (A)
            }   // if

            else
            {
                expire_flag=false;
                if (NULL!=options && NULL!=options->expiry_module.get())
                    expire_flag=options->expiry_module->KeyRetirementCallback(ikey);

                if ((ikey.type == kTypeDeletion || expire_flag)
                    && ikey.sequence <= smallest_snapshot
                    && NULL!=compaction  // mem to level0 ignores this test
                    && compaction->IsBaseLevelForKey(ikey.user_key))
                {
                    // For this user key:
                    // (1) there is no data in higher levels
                    // (2) data in lower levels will have larger sequence numbers
                    // (3) data in layers that are being compacted here and have
                    //     smaller sequence numbers will be dropped in the next
                    //     few iterations of this loop (by rule (A) above).
                    // Therefore this deletion marker is obsolete and can be dropped.
                    drop = true;

                    if (expire_flag)
                        ++expired;
                    else
                        ++dropped;
                }   // if
            }   // else

            last_sequence_for_key = ikey.sequence;
        }   // else
    }   // if

#if 0
    // needs clean up to be used again
    Log(options_.info_log,
        "  Compact: %s, seq %d, type: %d %d, drop: %d, is_base: %d, "
        "%d smallest_snapshot: %d",
        ikey.user_key.ToString().c_str(),
        (int)ikey.sequence, ikey.type, kTypeValue, drop,
        compact->compaction->IsBaseLevelForKey(ikey.user_key),
        (int)last_sequence_for_key, (int)compact->smallest_snapshot);
#endif
    return(drop);

}   // KeyRetirement::operator(Slice & )

}  // namespace leveldb
<|endoftext|>


<commit_before>#include "helper-funcs.hpp"

#include "mbed.h"
#include "rtos.h"

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
    __disable_irq();

    //set two bits for preemptive data, two bits for priority as the
    //structure for the IPRs. Grouping is global withing the IPRs so
    //this value should only be changed here.
    NVIC_SetPriorityGrouping(5);
    uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

    //set preemptive priority default to 2 (0..3)
    //set priority default to 1 (0..3)
    uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

    //When the kernel initialzes the PNVIC, all ISRs are set to the
    //highest priority, making it impossible to elevate a few over
    //the rest, so the default priority is lowered globally for the
    //table first.
    //
    //Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
    //specific
    for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
        NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);

    ////////////////////////////////////
    //  begin raise priority section  //
    ////////////////////////////////////

    //reestablish watchdog
    NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

    //TODO raise radio
    //TODO raise others after discussion

    ////////////////////////////////////
    //  begin lower priotity section  //
    ////////////////////////////////////

    //set UART (console) interrupts to minimal priority
    //when debugging radio and other time sensitive operations, this
    //interrupt will need to be deferred.
    NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 0));
    NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
    NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
    NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

    //TODO lower others after discussion

    //NVIC_EnableIRQ(TIMER0_IRQn);
    //NVIC_EnableIRQ(TIMER1_IRQn);
    //NVIC_EnableIRQ(TIMER2_IRQn);
    //NVIC_EnableIRQ(TIMER3_IRQn);

    __enable_irq();
}

/**
 * Timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive(void const* args)
{
    DigitalOut* led = (DigitalOut*)args;

    *led = !(*led);
    Thread::wait(50);
    *led = !(*led);
}

std::string decode_marcstate(uint8_t b)
{
    std::string state;

    switch (b & 0x1F) {
        case 0x00:
            state = "SLEEP";
            break;

        case 0x01:
            state = "IDLE";
            break;

        case 0x02:
            state = "XOFF";
            break;

        case 0x03:
            state = "BIAS_SETTLE_MC";
            break;

        case 0x04:
            state = "REG_SETTLE_MC";
            break;

        case 0x05:
            state = "MANCAL";
            break;

        case 0x06:
            state = "BIAS_SETTLE";
            break;

        case 0x07:
            state = "REG_SETTLE";
            break;

        case 0x08:
            state = "STARTCAL";
            break;

        case 0x09:
            state = "BWBOOST";
            break;

        case 0x0A:
            state = "FS_LOCK";
            break;

        case 0x0B:
            state = "IFADCON";
            break;

        case 0x0C:
            state = "ENDCAL";
            break;

        case 0x0D:
            state = "RX";
            break;

        case 0x0E:
            state = "RX_END";
            break;

        case 0x0F:
            state = "RXDCM";
            break;

        case 0x10:
            state = "TXRX_SWITCH";
            break;

        case 0x11:
            state = "RX_FIFO_ERR";
            break;

        case 0x12:
            state = "FSTXON";
            break;

        case 0x13:
            state = "TX";
            break;

        case 0x14:
            state = "TX_END";
            break;

        case 0x15:
            state = "RXTX_SWITCH";
            break;

        case 0x16:
            state = "TX_FIFO_ERR";
            break;

        case 0x17:
            state = "IFADCON_TXRX";
            break;

        default:
            state = "ERROR DECODING STATE";
            break;
    }

    return state;
}
<commit_msg>updating interrupt priority function<commit_after>#include "helper-funcs.hpp"

#include "mbed.h"
#include "rtos.h"

#include "logger.hpp"

/**
 * Initializes the peripheral nested vector interrupt controller (PNVIC) with
 * appropriate values. Low values have the higest priority (with system
 * interrupts having negative priority). All maskable interrupts are
 * diabled; do not intialize any interrupt frameworks before this funtion is
 * called. PNVIC interrupt priorities are independent of thread and NVIC
 * priorities.
 *
 * The PNVIC is independent of the NVIC responsible for system NMI's. The NVIC
 * is not accissable through the library, so in this context the NVIC functions
 * refer to the PNVIC. The configuration system for PNVIC priorities is strange
 * and different from X86. If you haven't already, look over
 * doc/ARM-Cortex-M_Interrupt-Priorities.pdf from RJ root and the online
 * documentation regarding Interrupt Priority Registers (IPRs) first.
 */
void setISRPriorities(void)
{
    __disable_irq();

    //set two bits for preemptive data, two bits for priority as the
    //structure for the IPRs. Grouping is global withing the IPRs so
    //this value should only be changed here.
    NVIC_SetPriorityGrouping(5);
    uint32_t priorityGrouping = NVIC_GetPriorityGrouping();

    //set preemptive priority default to 2 (0..3)
    //set priority default to 1 (0..3)
    uint32_t defaultPriority = NVIC_EncodePriority(priorityGrouping, 2, 1);

    //When the kernel initialzes the PNVIC, all ISRs are set to the
    //highest priority, making it impossible to elevate a few over
    //the rest, so the default priority is lowered globally for the
    //table first.
    //
    //Consult LPC17xx.h under IRQn_Type for PNVIC ranges, this is LPC1768
    //specific
    for (uint32_t IRQn = TIMER0_IRQn; IRQn <= CANActivity_IRQn; IRQn++)
        NVIC_SetPriority((IRQn_Type) IRQn, defaultPriority);

    ////////////////////////////////////
    //  begin raise priority section  //
    ////////////////////////////////////

    // reestablish watchdog
    NVIC_SetPriority(WDT_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 0));

    // reestablish timers
    // NVIC_SetPriority(TIMER0_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 1));
    // NVIC_SetPriority(TIMER1_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 2));
    // NVIC_SetPriority(TIMER2_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 3));
    // NVIC_SetPriority(TIMER3_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 4));

    // make TIMER #2 2nd in line t the watchdog timer
    NVIC_SetPriority(TIMER2_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 1));

    // this is the timer used in the mbed Ticker library
    NVIC_SetPriority(TIMER3_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 2));

    NVIC_SetPriority(I2C2_IRQn, NVIC_EncodePriority(priorityGrouping, 0, 3));

    ////////////////////////////////////
    //  begin lower priotity section  //
    ////////////////////////////////////

    //set UART (console) interrupts to minimal priority
    //when debugging radio and other time sensitive operations, this
    //interrupt will need to be deferred.
    NVIC_SetPriority(UART0_IRQn, NVIC_EncodePriority(priorityGrouping, 1, 0));

    // NVIC_SetPriority(UART1_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
    // NVIC_SetPriority(UART2_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 2));
    // NVIC_SetPriority(UART3_IRQn, NVIC_EncodePriority(priorityGrouping, 3, 1));

    // NVIC_EnableIRQ(TIMER0_IRQn);
    // NVIC_EnableIRQ(TIMER1_IRQn);
    // NVIC_EnableIRQ(TIMER2_IRQn);
    // NVIC_EnableIRQ(TIMER3_IRQn);

    __enable_irq();
}

/**
 * Timer interrupt based light flicker. If this stops, the code triggered
 * a fault.
 */
void imAlive(void const* args)
{
    DigitalOut* led = (DigitalOut*)args;

    *led = !(*led);
    Thread::wait(50);
    *led = !(*led);
}

std::string decode_marcstate(uint8_t b)
{
    std::string state;

    switch (b & 0x1F) {
        case 0x00:
            state = "SLEEP";
            break;

        case 0x01:
            state = "IDLE";
            break;

        case 0x02:
            state = "XOFF";
            break;

        case 0x03:
            state = "BIAS_SETTLE_MC";
            break;

        case 0x04:
            state = "REG_SETTLE_MC";
            break;

        case 0x05:
            state = "MANCAL";
            break;

        case 0x06:
            state = "BIAS_SETTLE";
            break;

        case 0x07:
            state = "REG_SETTLE";
            break;

        case 0x08:
            state = "STARTCAL";
            break;

        case 0x09:
            state = "BWBOOST";
            break;

        case 0x0A:
            state = "FS_LOCK";
            break;

        case 0x0B:
            state = "IFADCON";
            break;

        case 0x0C:
            state = "ENDCAL";
            break;

        case 0x0D:
            state = "RX";
            break;

        case 0x0E:
            state = "RX_END";
            break;

        case 0x0F:
            state = "RXDCM";
            break;

        case 0x10:
            state = "TXRX_SWITCH";
            break;

        case 0x11:
            state = "RX_FIFO_ERR";
            break;

        case 0x12:
            state = "FSTXON";
            break;

        case 0x13:
            state = "TX";
            break;

        case 0x14:
            state = "TX_END";
            break;

        case 0x15:
            state = "RXTX_SWITCH";
            break;

        case 0x16:
            state = "TX_FIFO_ERR";
            break;

        case 0x17:
            state = "IFADCON_TXRX";
            break;

        default:
            state = "ERROR DECODING STATE";
            break;
    }

    return state;
}
<|endoftext|>


<commit_before>/*
 * 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.
 */

/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "types.hh"
#include "tracing/trace_keyspace_helper.hh"
#include "service/migration_manager.hh"
#include "cql3/statements/create_table_statement.hh"

namespace tracing {

static logging::logger logger("trace_keyspace_helper");

const sstring trace_keyspace_helper::KEYSPACE_NAME("system_traces");
const sstring trace_keyspace_helper::SESSIONS("sessions");
const sstring trace_keyspace_helper::EVENTS("events");

trace_keyspace_helper::trace_keyspace_helper(tracing& tr)
            : i_tracing_backend_helper(tr)
            , _registrations{
        scollectd::add_polled_metric(scollectd::type_instance_id("tracing_keyspace_helper"
                        , scollectd::per_cpu_plugin_instance
                        , "total_operations", "tracing_errors")
                        , scollectd::make_typed(scollectd::data_type::DERIVE, _stats.tracing_errors)),
        scollectd::add_polled_metric(scollectd::type_instance_id("tracing_keyspace_helper"
                        , scollectd::per_cpu_plugin_instance
                        , "total_operations", "bad_column_family_errors")
                        , scollectd::make_typed(scollectd::data_type::DERIVE, _stats.bad_column_family_errors))} {

        _sessions_create_cql = sprint("CREATE TABLE %s.%s ("
                                      "session_id uuid,"
                                      "command text,"
                                      "client inet,"
                                      "coordinator inet,"
                                      "duration int,"
                                      "parameters map<text, text>,"
                                      "request text,"
                                      "started_at timestamp,"
                                      "PRIMARY KEY ((session_id)))", KEYSPACE_NAME, SESSIONS);

        _events_create_cql = sprint("CREATE TABLE %s.%s ("
                                    "session_id uuid,"
                                    "event_id timeuuid,"
                                    "activity text,"
                                    "source inet,"
                                    "source_elapsed int,"
                                    "thread text,"
                                    "PRIMARY KEY ((session_id), event_id))", KEYSPACE_NAME, EVENTS);
}

future<> trace_keyspace_helper::setup_table(const sstring& name, const sstring& cql) const {
    auto& qp = cql3::get_local_query_processor();
    auto& db = qp.db().local();

    if (db.has_schema(KEYSPACE_NAME, name)) {
        return make_ready_future<>();
    }

    // We don't care it it fails really - this may happen due to concurrent
    // "CREATE TABLE" invocation on different Nodes.
    // The important thing is that it will converge eventually (some traces may
    // be lost in a process but that's ok).
    return qp.process(cql, db::consistency_level::ONE).discard_result().handle_exception([this] (auto ep) {});
}

bool trace_keyspace_helper::cache_sessions_table_handles(const schema_ptr& schema) {
    auto session_id_column = schema->get_column_definition("session_id");
    _client_column = schema->get_column_definition("client");
    _coordinator_column = schema->get_column_definition("coordinator");
    _request_column = schema->get_column_definition("request");
    _started_at_column = schema->get_column_definition("started_at");
    _command_column = schema->get_column_definition("command");
    _duration_column = schema->get_column_definition("duration");
    _parameters_column = schema->get_column_definition("parameters");

    if (session_id_column && session_id_column->type == uuid_type &&
        _client_column && _client_column->type == inet_addr_type &&
        _coordinator_column && _coordinator_column->type == inet_addr_type &&
        _request_column && _request_column->type == utf8_type &&
        _started_at_column && _started_at_column->type == timestamp_type &&
        _command_column && _command_column->type == utf8_type &&
        _duration_column && _duration_column->type == int32_type &&
        _parameters_column && _parameters_column->type && map_type_impl::get_instance(utf8_type, utf8_type, true)) {
        // store a table ID only if its format meets our demands
        _sessions_id = schema->id();
        return true;
    } else {
        _sessions_id = utils::UUID();
        return false;
    }
}

bool trace_keyspace_helper::cache_events_table_handles(const schema_ptr& schema) {
    auto session_id_column = schema->get_column_definition("session_id");
    auto event_id_column = schema->get_column_definition("event_id");
    _activity_column = schema->get_column_definition("activity");
    _source_column = schema->get_column_definition("source");
    _thread_column = schema->get_column_definition("thread");
    _source_elapsed_column = schema->get_column_definition("source_elapsed");

    if (session_id_column && session_id_column->type == uuid_type &&
        event_id_column && event_id_column->type == timeuuid_type &&
        _activity_column && _activity_column->type == utf8_type &&
        _source_column && _source_column->type == inet_addr_type &&
        _thread_column && _thread_column->type == utf8_type &&
        _source_elapsed_column && _source_elapsed_column->type == int32_type) {
        // store a table ID only if its format meets our demands
        _events_id = schema->id();
        return true;
    } else {
        _events_id = utils::UUID();
        return false;
    }
}

future<> trace_keyspace_helper::start() {
    if (engine().cpu_id() == 0) {
        return seastar::async([this] {
            auto& db = cql3::get_local_query_processor().db().local();

            // Create a keyspace
            if (!db.has_keyspace(KEYSPACE_NAME)) {
                std::map<sstring, sstring> opts;
                opts["replication_factor"] = "2";
                auto ksm = keyspace_metadata::new_keyspace(KEYSPACE_NAME, "org.apache.cassandra.locator.SimpleStrategy", std::move(opts), true);
                service::get_local_migration_manager().announce_new_keyspace(ksm, false).get();
            }

            // Create tables
            setup_table(SESSIONS, _sessions_create_cql).get();
            setup_table(EVENTS, _events_create_cql).get();
        });
    } else {
        return make_ready_future<>();
    }
}

void trace_keyspace_helper::write_session_record(const utils::UUID& session_id,
                                                 gms::inet_address client,
                                                 std::unordered_map<sstring, sstring> parameters,
                                                 sstring request,
                                                 long started_at,
                                                 trace_type command,
                                                 int elapsed,
                                                 gc_clock::duration ttl) {
    try {
        _mutation_makers[session_id].first = [request = std::move(request), client, parameters = std::move(parameters), started_at, command, elapsed, ttl, this] (const utils::UUID& session_id) {
            return make_session_mutation(session_id, client, parameters, request, started_at, type_to_string(command), elapsed, ttl);
        };
    } catch (...) {
        // OOM: ignore
    }
}

void trace_keyspace_helper::write_event_record(const utils::UUID& session_id,
                                               sstring message,
                                               int elapsed,
                                               gc_clock::duration ttl,
                                               wall_clock::time_point event_time_point) {
    try {
        _mutation_makers[session_id].second.makers.emplace_back([message = std::move(message), elapsed, ttl, event_time_point, this] (const utils::UUID& session_id) mutable {
            return make_event_mutation(session_id, message, elapsed, _local_tracing.get_thread_name(), ttl, event_time_point);
        });
    } catch (...) {
        // OOM: ignore
    }
}

mutation trace_keyspace_helper::make_session_mutation(
        const utils::UUID& session_id,
        gms::inet_address client,
        const std::unordered_map<sstring, sstring>& parameters,
        const sstring& request,
        long started_at,
        const sstring& command,
        int elapsed,
        gc_clock::duration ttl) {
    schema_ptr schema = get_schema_ptr_or_create(_sessions_id, SESSIONS, _sessions_create_cql,
                                                 [this] (const schema_ptr& s) { return cache_sessions_table_handles(s); });

    auto key = partition_key::from_singular(*schema, session_id);
    auto timestamp = api::new_timestamp();
    mutation m(key, schema);
    auto& cells = m.partition().clustered_row(clustering_key::make_empty(*schema)).cells();

    cells.apply(*_client_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(client.addr()), ttl));
    cells.apply(*_coordinator_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(utils::fb_utilities::get_broadcast_address().addr()), ttl));
    cells.apply(*_request_column, atomic_cell::make_live(timestamp, utf8_type->decompose(request), ttl));
    cells.apply(*_started_at_column, atomic_cell::make_live(timestamp, timestamp_type->decompose(started_at), ttl));
    cells.apply(*_command_column, atomic_cell::make_live(timestamp, utf8_type->decompose(command), ttl));
    cells.apply(*_duration_column, atomic_cell::make_live(timestamp, int32_type->decompose((int32_t)elapsed), ttl));

    std::vector<std::pair<bytes, atomic_cell>> map_cell;
    for (auto& param_pair : parameters) {
        map_cell.emplace_back(utf8_type->decompose(param_pair.first), atomic_cell::make_live(timestamp, utf8_type->decompose(param_pair.second), ttl));
    }

    map_type_impl::mutation map_mutation{{}, map_cell};
    auto my_map_type = map_type_impl::get_instance(utf8_type, utf8_type, true);
    cells.apply(*_parameters_column, my_map_type->serialize_mutation_form(map_mutation));

    return m;
}

mutation trace_keyspace_helper::make_event_mutation(const utils::UUID& session_id,
                                                    const sstring& message,
                                                    int elapsed,
                                                    const sstring& thread_name,
                                                    gc_clock::duration ttl,
                                                    wall_clock::time_point event_time_point) {
    schema_ptr schema = get_schema_ptr_or_create(_events_id, EVENTS, _events_create_cql,
                                                 [this] (const schema_ptr& s) { return cache_events_table_handles(s); });

    auto key = partition_key::from_singular(*schema, session_id);
    auto timestamp = api::new_timestamp();
    mutation m(key, schema);
    auto& cells = m.partition().clustered_row(clustering_key::from_singular(*schema, utils::UUID_gen::get_time_UUID(make_monotonic_UUID_tp(event_time_point)))).cells();

    cells.apply(*_activity_column, atomic_cell::make_live(timestamp, utf8_type->decompose(message), ttl));
    cells.apply(*_source_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(utils::fb_utilities::get_broadcast_address().addr()), ttl));
    cells.apply(*_thread_column, atomic_cell::make_live(timestamp, utf8_type->decompose(thread_name), ttl));

    assert(elapsed >= 0);
    cells.apply(*_source_elapsed_column, atomic_cell::make_live(timestamp, int32_type->decompose(elapsed), ttl));

    return m;
}

future<> trace_keyspace_helper::flush_one_session_mutations(utils::UUID session_id, std::pair<mutation_maker, events_mutation_makers>& mutation_makers) {
    return make_ready_future<>().then([this, session_id, events_makers = std::move(mutation_makers.second.makers)] {
        if (events_makers.size()) {
            // Reset the "monotinic time point" state machine since it's
            // relevant in a context of a single tracing session only. The
            // events from different sessions will differ by a session UUID.
            reset_monotonic_tp();
            logger.trace("{}: events number is {}", session_id, events_makers.size());
            mutation m((*events_makers.begin())(session_id));
            std::for_each(std::next(events_makers.begin()), events_makers.end(), [&m, &session_id] (const mutation_maker& maker) mutable { m.apply(maker(session_id)); });
            return service::get_local_storage_proxy().mutate({std::move(m)}, db::consistency_level::ANY, nullptr);
        } else {
            return make_ready_future<>();
        }
    }).then([session_id = std::move(session_id), session_maker = std::move(mutation_makers.first)] {
        if (session_maker) {
            logger.trace("{}: storing a session event", session_id);
            return service::get_local_storage_proxy().mutate({session_maker(session_id)}, db::consistency_level::ANY, nullptr);
        } else {
            return make_ready_future<>();
        }
    });
}

void trace_keyspace_helper::kick() {
    logger.trace("flushing {} sessions", _mutation_makers.size());
    parallel_for_each(_mutation_makers,[this](decltype(_mutation_makers)::value_type& uuid_mutation_makers) {
        return with_gate(_pending_writes, [this, &uuid_mutation_makers]  {
            logger.trace("{}: flushing traces", uuid_mutation_makers.first);
            return this->flush_one_session_mutations(uuid_mutation_makers.first, uuid_mutation_makers.second).finally([this] { _local_tracing.write_complete(); });
        }).handle_exception([this] (auto ep) {
            try {
                ++_stats.tracing_errors;
                std::rethrow_exception(ep);
            } catch (exceptions::overloaded_exception&) {
                logger.warn("Too many nodes are overloaded to save trace events");
            } catch (bad_column_family& e) {
                if (_stats.bad_column_family_errors++ % bad_column_family_message_period == 0) {
                    logger.warn("Tracing is enabled but {}", e.what());
                }
            } catch (...) {
                // TODO: Handle some more exceptions maybe?
            }
        });
    }).discard_result();

    // We can clear the hash table here because we cared to capture all relevant
    // data from it in lambdas' capture-lists inside
    // flush_one_session_mutations() before any asynchronous call.
    _mutation_makers.clear();
}

using registry = class_registrator<i_tracing_backend_helper, trace_keyspace_helper, tracing&>;
static registry registrator1("trace_keyspace_helper");

}
<commit_msg>tracing: set a default TTL for system_traces tables when they are created<commit_after>/*
 * 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.
 */

/*
 * Copyright (C) 2016 ScyllaDB
 *
 * Modified by ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "types.hh"
#include "tracing/trace_keyspace_helper.hh"
#include "service/migration_manager.hh"
#include "cql3/statements/create_table_statement.hh"

namespace tracing {

static logging::logger logger("trace_keyspace_helper");

const sstring trace_keyspace_helper::KEYSPACE_NAME("system_traces");
const sstring trace_keyspace_helper::SESSIONS("sessions");
const sstring trace_keyspace_helper::EVENTS("events");

trace_keyspace_helper::trace_keyspace_helper(tracing& tr)
            : i_tracing_backend_helper(tr)
            , _registrations{
        scollectd::add_polled_metric(scollectd::type_instance_id("tracing_keyspace_helper"
                        , scollectd::per_cpu_plugin_instance
                        , "total_operations", "tracing_errors")
                        , scollectd::make_typed(scollectd::data_type::DERIVE, _stats.tracing_errors)),
        scollectd::add_polled_metric(scollectd::type_instance_id("tracing_keyspace_helper"
                        , scollectd::per_cpu_plugin_instance
                        , "total_operations", "bad_column_family_errors")
                        , scollectd::make_typed(scollectd::data_type::DERIVE, _stats.bad_column_family_errors))} {

        _sessions_create_cql = sprint("CREATE TABLE %s.%s ("
                                      "session_id uuid,"
                                      "command text,"
                                      "client inet,"
                                      "coordinator inet,"
                                      "duration int,"
                                      "parameters map<text, text>,"
                                      "request text,"
                                      "started_at timestamp,"
                                      "PRIMARY KEY ((session_id))) "
                                      "WITH default_time_to_live = 86400", KEYSPACE_NAME, SESSIONS);

        _events_create_cql = sprint("CREATE TABLE %s.%s ("
                                    "session_id uuid,"
                                    "event_id timeuuid,"
                                    "activity text,"
                                    "source inet,"
                                    "source_elapsed int,"
                                    "thread text,"
                                    "PRIMARY KEY ((session_id), event_id)) "
                                    "WITH default_time_to_live = 86400", KEYSPACE_NAME, EVENTS);
}

future<> trace_keyspace_helper::setup_table(const sstring& name, const sstring& cql) const {
    auto& qp = cql3::get_local_query_processor();
    auto& db = qp.db().local();

    if (db.has_schema(KEYSPACE_NAME, name)) {
        return make_ready_future<>();
    }

    // We don't care it it fails really - this may happen due to concurrent
    // "CREATE TABLE" invocation on different Nodes.
    // The important thing is that it will converge eventually (some traces may
    // be lost in a process but that's ok).
    return qp.process(cql, db::consistency_level::ONE).discard_result().handle_exception([this] (auto ep) {});
}

bool trace_keyspace_helper::cache_sessions_table_handles(const schema_ptr& schema) {
    auto session_id_column = schema->get_column_definition("session_id");
    _client_column = schema->get_column_definition("client");
    _coordinator_column = schema->get_column_definition("coordinator");
    _request_column = schema->get_column_definition("request");
    _started_at_column = schema->get_column_definition("started_at");
    _command_column = schema->get_column_definition("command");
    _duration_column = schema->get_column_definition("duration");
    _parameters_column = schema->get_column_definition("parameters");

    if (session_id_column && session_id_column->type == uuid_type &&
        _client_column && _client_column->type == inet_addr_type &&
        _coordinator_column && _coordinator_column->type == inet_addr_type &&
        _request_column && _request_column->type == utf8_type &&
        _started_at_column && _started_at_column->type == timestamp_type &&
        _command_column && _command_column->type == utf8_type &&
        _duration_column && _duration_column->type == int32_type &&
        _parameters_column && _parameters_column->type && map_type_impl::get_instance(utf8_type, utf8_type, true)) {
        // store a table ID only if its format meets our demands
        _sessions_id = schema->id();
        return true;
    } else {
        _sessions_id = utils::UUID();
        return false;
    }
}

bool trace_keyspace_helper::cache_events_table_handles(const schema_ptr& schema) {
    auto session_id_column = schema->get_column_definition("session_id");
    auto event_id_column = schema->get_column_definition("event_id");
    _activity_column = schema->get_column_definition("activity");
    _source_column = schema->get_column_definition("source");
    _thread_column = schema->get_column_definition("thread");
    _source_elapsed_column = schema->get_column_definition("source_elapsed");

    if (session_id_column && session_id_column->type == uuid_type &&
        event_id_column && event_id_column->type == timeuuid_type &&
        _activity_column && _activity_column->type == utf8_type &&
        _source_column && _source_column->type == inet_addr_type &&
        _thread_column && _thread_column->type == utf8_type &&
        _source_elapsed_column && _source_elapsed_column->type == int32_type) {
        // store a table ID only if its format meets our demands
        _events_id = schema->id();
        return true;
    } else {
        _events_id = utils::UUID();
        return false;
    }
}

future<> trace_keyspace_helper::start() {
    if (engine().cpu_id() == 0) {
        return seastar::async([this] {
            auto& db = cql3::get_local_query_processor().db().local();

            // Create a keyspace
            if (!db.has_keyspace(KEYSPACE_NAME)) {
                std::map<sstring, sstring> opts;
                opts["replication_factor"] = "2";
                auto ksm = keyspace_metadata::new_keyspace(KEYSPACE_NAME, "org.apache.cassandra.locator.SimpleStrategy", std::move(opts), true);
                service::get_local_migration_manager().announce_new_keyspace(ksm, false).get();
            }

            // Create tables
            setup_table(SESSIONS, _sessions_create_cql).get();
            setup_table(EVENTS, _events_create_cql).get();
        });
    } else {
        return make_ready_future<>();
    }
}

void trace_keyspace_helper::write_session_record(const utils::UUID& session_id,
                                                 gms::inet_address client,
                                                 std::unordered_map<sstring, sstring> parameters,
                                                 sstring request,
                                                 long started_at,
                                                 trace_type command,
                                                 int elapsed,
                                                 gc_clock::duration ttl) {
    try {
        _mutation_makers[session_id].first = [request = std::move(request), client, parameters = std::move(parameters), started_at, command, elapsed, ttl, this] (const utils::UUID& session_id) {
            return make_session_mutation(session_id, client, parameters, request, started_at, type_to_string(command), elapsed, ttl);
        };
    } catch (...) {
        // OOM: ignore
    }
}

void trace_keyspace_helper::write_event_record(const utils::UUID& session_id,
                                               sstring message,
                                               int elapsed,
                                               gc_clock::duration ttl,
                                               wall_clock::time_point event_time_point) {
    try {
        _mutation_makers[session_id].second.makers.emplace_back([message = std::move(message), elapsed, ttl, event_time_point, this] (const utils::UUID& session_id) mutable {
            return make_event_mutation(session_id, message, elapsed, _local_tracing.get_thread_name(), ttl, event_time_point);
        });
    } catch (...) {
        // OOM: ignore
    }
}

mutation trace_keyspace_helper::make_session_mutation(
        const utils::UUID& session_id,
        gms::inet_address client,
        const std::unordered_map<sstring, sstring>& parameters,
        const sstring& request,
        long started_at,
        const sstring& command,
        int elapsed,
        gc_clock::duration ttl) {
    schema_ptr schema = get_schema_ptr_or_create(_sessions_id, SESSIONS, _sessions_create_cql,
                                                 [this] (const schema_ptr& s) { return cache_sessions_table_handles(s); });

    auto key = partition_key::from_singular(*schema, session_id);
    auto timestamp = api::new_timestamp();
    mutation m(key, schema);
    auto& cells = m.partition().clustered_row(clustering_key::make_empty(*schema)).cells();

    cells.apply(*_client_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(client.addr()), ttl));
    cells.apply(*_coordinator_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(utils::fb_utilities::get_broadcast_address().addr()), ttl));
    cells.apply(*_request_column, atomic_cell::make_live(timestamp, utf8_type->decompose(request), ttl));
    cells.apply(*_started_at_column, atomic_cell::make_live(timestamp, timestamp_type->decompose(started_at), ttl));
    cells.apply(*_command_column, atomic_cell::make_live(timestamp, utf8_type->decompose(command), ttl));
    cells.apply(*_duration_column, atomic_cell::make_live(timestamp, int32_type->decompose((int32_t)elapsed), ttl));

    std::vector<std::pair<bytes, atomic_cell>> map_cell;
    for (auto& param_pair : parameters) {
        map_cell.emplace_back(utf8_type->decompose(param_pair.first), atomic_cell::make_live(timestamp, utf8_type->decompose(param_pair.second), ttl));
    }

    map_type_impl::mutation map_mutation{{}, map_cell};
    auto my_map_type = map_type_impl::get_instance(utf8_type, utf8_type, true);
    cells.apply(*_parameters_column, my_map_type->serialize_mutation_form(map_mutation));

    return m;
}

mutation trace_keyspace_helper::make_event_mutation(const utils::UUID& session_id,
                                                    const sstring& message,
                                                    int elapsed,
                                                    const sstring& thread_name,
                                                    gc_clock::duration ttl,
                                                    wall_clock::time_point event_time_point) {
    schema_ptr schema = get_schema_ptr_or_create(_events_id, EVENTS, _events_create_cql,
                                                 [this] (const schema_ptr& s) { return cache_events_table_handles(s); });

    auto key = partition_key::from_singular(*schema, session_id);
    auto timestamp = api::new_timestamp();
    mutation m(key, schema);
    auto& cells = m.partition().clustered_row(clustering_key::from_singular(*schema, utils::UUID_gen::get_time_UUID(make_monotonic_UUID_tp(event_time_point)))).cells();

    cells.apply(*_activity_column, atomic_cell::make_live(timestamp, utf8_type->decompose(message), ttl));
    cells.apply(*_source_column, atomic_cell::make_live(timestamp, inet_addr_type->decompose(utils::fb_utilities::get_broadcast_address().addr()), ttl));
    cells.apply(*_thread_column, atomic_cell::make_live(timestamp, utf8_type->decompose(thread_name), ttl));

    assert(elapsed >= 0);
    cells.apply(*_source_elapsed_column, atomic_cell::make_live(timestamp, int32_type->decompose(elapsed), ttl));

    return m;
}

future<> trace_keyspace_helper::flush_one_session_mutations(utils::UUID session_id, std::pair<mutation_maker, events_mutation_makers>& mutation_makers) {
    return make_ready_future<>().then([this, session_id, events_makers = std::move(mutation_makers.second.makers)] {
        if (events_makers.size()) {
            // Reset the "monotinic time point" state machine since it's
            // relevant in a context of a single tracing session only. The
            // events from different sessions will differ by a session UUID.
            reset_monotonic_tp();
            logger.trace("{}: events number is {}", session_id, events_makers.size());
            mutation m((*events_makers.begin())(session_id));
            std::for_each(std::next(events_makers.begin()), events_makers.end(), [&m, &session_id] (const mutation_maker& maker) mutable { m.apply(maker(session_id)); });
            return service::get_local_storage_proxy().mutate({std::move(m)}, db::consistency_level::ANY, nullptr);
        } else {
            return make_ready_future<>();
        }
    }).then([session_id = std::move(session_id), session_maker = std::move(mutation_makers.first)] {
        if (session_maker) {
            logger.trace("{}: storing a session event", session_id);
            return service::get_local_storage_proxy().mutate({session_maker(session_id)}, db::consistency_level::ANY, nullptr);
        } else {
            return make_ready_future<>();
        }
    });
}

void trace_keyspace_helper::kick() {
    logger.trace("flushing {} sessions", _mutation_makers.size());
    parallel_for_each(_mutation_makers,[this](decltype(_mutation_makers)::value_type& uuid_mutation_makers) {
        return with_gate(_pending_writes, [this, &uuid_mutation_makers]  {
            logger.trace("{}: flushing traces", uuid_mutation_makers.first);
            return this->flush_one_session_mutations(uuid_mutation_makers.first, uuid_mutation_makers.second).finally([this] { _local_tracing.write_complete(); });
        }).handle_exception([this] (auto ep) {
            try {
                ++_stats.tracing_errors;
                std::rethrow_exception(ep);
            } catch (exceptions::overloaded_exception&) {
                logger.warn("Too many nodes are overloaded to save trace events");
            } catch (bad_column_family& e) {
                if (_stats.bad_column_family_errors++ % bad_column_family_message_period == 0) {
                    logger.warn("Tracing is enabled but {}", e.what());
                }
            } catch (...) {
                // TODO: Handle some more exceptions maybe?
            }
        });
    }).discard_result();

    // We can clear the hash table here because we cared to capture all relevant
    // data from it in lambdas' capture-lists inside
    // flush_one_session_mutations() before any asynchronous call.
    _mutation_makers.clear();
}

using registry = class_registrator<i_tracing_backend_helper, trace_keyspace_helper, tracing&>;
static registry registrator1("trace_keyspace_helper");

}
<|endoftext|>