<commit_before>#include "ros/ros.h"
#include "std_msgs/String.h"
#include "sensor_msgs/PointCloud2.h"
#include <pcl/point_types.h>
#include <pcl_ros/transforms.h>
#include <pcl/conversions.h>
#include <pcl/PCLPointCloud2.h>
#include <cstdio>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/conversions.h>
#include <pcl/point_cloud.h>

// camera_link for fixed frame in global option in rviz

/* define what kind of point clouds we're using */
typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloudT;

bool new_cloud_available_flag = false;

// General point cloud to store the whole image
PointCloudT::Ptr cloud (new PointCloudT);

//Point Cloud to store out neon cap
PointCloudT::Ptr neon_cloud (new PointCloudT);

// Message required to publish the cloud - Convert from pcl to msg
sensor_msgs::PointCloud2 cloud_ros;

void cloud_sub(const sensor_msgs::PointCloud2ConstPtr& msg)
{
		//convert the msg to PCL format
		pcl::fromROSMsg (*msg, *cloud);

		//state that a new cloud is available
		new_cloud_available_flag = true;

		/**PointCloudT::iterator myIterator;
		for(myIterator = cloud->begin();
			myIterator != cloud->end();
			myIterator++)
		{
			std::cout<<*myIterator<<" ";
		}**/
}

PointCloudT::Ptr computeNeonVoxels(PointCloudT::Ptr in) {
    int total_neon = 0;

    //Point Cloud to store out neon cap
	PointCloudT::Ptr temp_neon_cloud (new PointCloudT);

    for (int i = 0; i < in->points.size(); i++) {
        unsigned int r, g, b;
        r = in->points[i].r;
        g = in->points[i].g;
        b = in->points[i].b;
        // Look for mostly neon value points
        if (g > 150 && (r + b) < 250) {
			temp_neon_cloud->push_back(in->points[i]);
	    }
    }

    return temp_neon_cloud;
}

int main (int argc, char** argv)
{
	// Initialize ROS
	ros::init (argc, argv, "kinect_fun");
	ros::NodeHandle nh;

	// Create a ROS subscriber for the input point cloud
	ros::Subscriber sub = nh.subscribe ("/camera/depth_registered/points", 1000, cloud_sub);

	//debugging publisher --> can create your own topic and then subscribe to it through rviz
	ros::Publisher cloud_pub = nh.advertise<sensor_msgs::PointCloud2>("detect_cap/cloud", 10);

	//refresh rate
	double ros_rate = 3.0;
	ros::Rate r(ros_rate);

	while (ros::ok())
	{
		ros::spinOnce();
		r.sleep();

		if (new_cloud_available_flag){
			new_cloud_available_flag = false;

			ROS_INFO("Before voxel grid filter: %i points",(int)cloud->points.size());

			// Voxel Grid reduces the computation time. Its a good idea to do it if you will be doing
			//sequential processing or frame-by-frame
			// Create the filtering object: downsample the dataset using a leaf size of 1cm
			pcl::VoxelGrid<PointT> vg;
			pcl::PointCloud<PointT>::Ptr cloud_filtered (new pcl::PointCloud<PointT>);
			vg.setInputCloud (cloud);
			vg.setLeafSize (0.005f, 0.005f, 0.005f);
			vg.filter (*cloud_filtered);

			ROS_INFO("After voxel grid filter: %i points",(int)cloud_filtered->points.size());

			int max_num_neon = 0;

			//Send the filtered point cloud to be processed in order to get the neon blob
			neon_cloud = computeNeonVoxels(cloud_filtered);

			//Publish the cloud with the neon cap
			pcl::toROSMsg(*neon_cloud,cloud_ros);

			//Set the frame ID to the first cloud we took in coz we want to replace that one
			cloud_ros.header.frame_id = cloud->header.frame_id;
			cloud_pub.publish(cloud_ros);

			// Find the centroid of the neon cap
			Eigen::Vector4f centroid;
			pcl::compute3DCentroid(*neon_cloud, centroid);

			ROS_INFO("The centroid of the neon cap is: (%f, %f, %f)", centroid(0), centroid(1), centroid(2));

		}
	}

	return 0;
}
<commit_msg>Provided code correction<commit_after>#include "ros/ros.h"
#include "std_msgs/String.h"
#include "sensor_msgs/PointCloud2.h"
#include <pcl/point_types.h>
#include <pcl_ros/transforms.h>
#include <pcl/conversions.h>
#include <pcl/PCLPointCloud2.h>
#include <cstdio>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/conversions.h>
#include <pcl/point_cloud.h>

// camera_link for fixed frame in global option in rviz

/* define what kind of point clouds we're using */
typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloudT;

bool new_cloud_available_flag = false;

// General point cloud to store the whole image
PointCloudT::Ptr cloud (new PointCloudT);

//Point Cloud to store out neon cap
PointCloudT::Ptr neon_cloud (new PointCloudT);

// Message required to publish the cloud - Convert from pcl to msg
sensor_msgs::PointCloud2 cloud_ros;

void cloud_sub(const sensor_msgs::PointCloud2ConstPtr& msg)
{
		//convert the msg to PCL format
		pcl::fromROSMsg (*msg, *cloud);

		//state that a new cloud is available
		new_cloud_available_flag = true;

		/**PointCloudT::iterator myIterator;
		for(myIterator = cloud->begin();
			myIterator != cloud->end();
			myIterator++)
		{
			std::cout<<*myIterator<<" ";
		}**/
}

PointCloudT::Ptr computeNeonVoxels(PointCloudT::Ptr in) {
    int total_neon = 0;

    //Point Cloud to store out neon cap
	PointCloudT::Ptr temp_neon_cloud (new PointCloudT);

    for (int i = 0; i < in->points.size(); i++) {
        unsigned int r, g, b;
        r = in->points[i].r;
        g = in->points[i].g;
        b = in->points[i].b;
        // Look for mostly neon value points
        if (g > 150 && (r + b) < 250) {
			temp_neon_cloud->push_back(in->points[i]);
	    }
    }

    return temp_neon_cloud;
}

int main (int argc, char** argv)
{
	// Initialize ROS
	ros::init (argc, argv, "kinect_fun");
	ros::NodeHandle nh;

	// Create a ROS subscriber for the input point cloud
	ros::Subscriber sub = nh.subscribe ("/nav_kinect/depth_registered/points", 1000, cloud_sub);

	//debugging publisher --> can create your own topic and then subscribe to it through rviz
	ros::Publisher cloud_pub = nh.advertise<sensor_msgs::PointCloud2>("detect_cap/cloud", 10);

	//refresh rate
	double ros_rate = 3.0;
	ros::Rate r(ros_rate);

	while (ros::ok())
	{
		ros::spinOnce();
		r.sleep();

		if (new_cloud_available_flag){
			new_cloud_available_flag = false;

			ROS_INFO("Before voxel grid filter: %i points",(int)cloud->points.size());

			// Voxel Grid reduces the computation time. Its a good idea to do it if you will be doing
			//sequential processing or frame-by-frame
			// Create the filtering object: downsample the dataset using a leaf size of 1cm
			pcl::VoxelGrid<PointT> vg;
			pcl::PointCloud<PointT>::Ptr cloud_filtered (new pcl::PointCloud<PointT>);
			vg.setInputCloud (cloud);
			vg.setLeafSize (0.005f, 0.005f, 0.005f);
			vg.filter (*cloud_filtered);

			ROS_INFO("After voxel grid filter: %i points",(int)cloud_filtered->points.size());

			int max_num_neon = 0;

			//Send the filtered point cloud to be processed in order to get the neon blob
			neon_cloud = computeNeonVoxels(cloud_filtered);

			//Publish the cloud with the neon cap
			pcl::toROSMsg(*neon_cloud,cloud_ros);

			//Set the frame ID to the first cloud we took in coz we want to replace that one
			cloud_ros.header.frame_id = cloud->header.frame_id;
			cloud_pub.publish(cloud_ros);

			// Find the centroid of the neon cap
			Eigen::Vector4f centroid;
			pcl::compute3DCentroid(*neon_cloud, centroid);

			ROS_INFO("The centroid of the neon cap is: (%f, %f, %f)", centroid(0), centroid(1), centroid(2));

		}
	}

	return 0;
}
<|endoftext|>


<commit_before>#include <algorithm>

#include <gtest/gtest.h>

#include "../readable_string_stream.h"

class ReadableStringStreamTests : public ::testing::Test {
protected:
    virtual void SetUp() {
        ResetBuffer();
    }

    virtual void TearDown() {

    }

    void ResetBuffer() { std::fill_n(buffer_, sizeof(buffer_), resetValue_); }

    const rs::httpserver::Stream::byte resetValue_ = 0xff;
    rs::httpserver::Stream::byte buffer_[1024];
};

TEST_F(ReadableStringStreamTests, TestEmptyStream) {
    rs::httpserver::ReadableStringStream stream("");
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);
}

TEST_F(ReadableStringStreamTests, TestShortStream1) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "1234";
    rs::httpserver::ReadableStringStream stream("1234");
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 0);

    // read all the available data
    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream2) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data
    int bytesRead = stream.Read(buffer_, 0, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream3) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // peek the first N bytes of the available data
    int bytesRead = stream.Read(buffer_, 0, 4, true);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek all remaining bytes of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], testData[4]);
    ASSERT_EQ(buffer_[5], testData[5]);
    ASSERT_EQ(buffer_[6], testData[6]);
    ASSERT_EQ(buffer_[7], testData[7]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read all bytes of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], testData[4]);
    ASSERT_EQ(buffer_[5], testData[5]);
    ASSERT_EQ(buffer_[6], testData[6]);
    ASSERT_EQ(buffer_[7], testData[7]);
    ASSERT_EQ(buffer_[8], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream4) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data at offset M
    int bytesRead = stream.Read(buffer_, 4, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], resetValue_);
    ASSERT_EQ(buffer_[1], resetValue_);
    ASSERT_EQ(buffer_[2], resetValue_);
    ASSERT_EQ(buffer_[3], resetValue_);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read the next N bytes of the available data at offset 0
    bytesRead = stream.Read(buffer_, 0, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream5) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    stream.AppendData("90123456");
    ASSERT_EQ(stream.getLength(), 16);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data at offset M
    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 16);
    ASSERT_EQ(stream.getLength(), 16);
    ASSERT_EQ(stream.getPosition(), 16);

    stream.AppendData("78901234");
    ASSERT_EQ(stream.getLength(), 24);
    ASSERT_EQ(stream.getPosition(), 16);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 24);
    ASSERT_EQ(stream.getPosition(), 24);
}

TEST_F(ReadableStringStreamTests, TestShortStream6) {
    rs::httpserver::ReadableStringStream stream("this is a placebo");

    ASSERT_THROW({
        stream.Write(buffer_, 0, sizeof(buffer_));
    }, rs::httpserver::InvalidStreamOperationException);
}<commit_msg>Added a Flush test to ReadableStringStream<commit_after>#include <algorithm>

#include <gtest/gtest.h>

#include "../readable_string_stream.h"

class ReadableStringStreamTests : public ::testing::Test {
protected:
    virtual void SetUp() {
        ResetBuffer();
    }

    virtual void TearDown() {

    }

    bool SanityCheckWhatMessage(const char* msg);

    void ResetBuffer() { std::fill_n(buffer_, sizeof(buffer_), resetValue_); }

    const rs::httpserver::Stream::byte resetValue_ = 0xff;
    rs::httpserver::Stream::byte buffer_[1024];
};

bool ReadableStringStreamTests::SanityCheckWhatMessage(const char* msg) {
    while (*msg != '\0') {
        if (*msg < 0x0d || *msg > 0x7e) {
            return false;
        }
        msg++;
    }
    return true;
}

TEST_F(ReadableStringStreamTests, TestEmptyStream) {
    rs::httpserver::ReadableStringStream stream("");
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 0);
    ASSERT_EQ(stream.getPosition(), 0);
}

TEST_F(ReadableStringStreamTests, TestShortStream1) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "1234";
    rs::httpserver::ReadableStringStream stream("1234");
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 0);

    // read all the available data
    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 4);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream2) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data
    int bytesRead = stream.Read(buffer_, 0, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream3) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // peek the first N bytes of the available data
    int bytesRead = stream.Read(buffer_, 0, 4, true);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], resetValue_);

    // peek all remaining bytes of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_), true);
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], testData[4]);
    ASSERT_EQ(buffer_[5], testData[5]);
    ASSERT_EQ(buffer_[6], testData[6]);
    ASSERT_EQ(buffer_[7], testData[7]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read all bytes of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[0]);
    ASSERT_EQ(buffer_[1], testData[1]);
    ASSERT_EQ(buffer_[2], testData[2]);
    ASSERT_EQ(buffer_[3], testData[3]);
    ASSERT_EQ(buffer_[4], testData[4]);
    ASSERT_EQ(buffer_[5], testData[5]);
    ASSERT_EQ(buffer_[6], testData[6]);
    ASSERT_EQ(buffer_[7], testData[7]);
    ASSERT_EQ(buffer_[8], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream4) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data at offset M
    int bytesRead = stream.Read(buffer_, 4, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 4);
    ASSERT_EQ(buffer_[0], resetValue_);
    ASSERT_EQ(buffer_[1], resetValue_);
    ASSERT_EQ(buffer_[2], resetValue_);
    ASSERT_EQ(buffer_[3], resetValue_);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read the next N bytes of the available data at offset 0
    bytesRead = stream.Read(buffer_, 0, 4);
    ASSERT_EQ(bytesRead, 4);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);

    // read over the end of the available data
    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 0);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 8);
    ASSERT_EQ(buffer_[0], testData[4]);
    ASSERT_EQ(buffer_[1], testData[5]);
    ASSERT_EQ(buffer_[2], testData[6]);
    ASSERT_EQ(buffer_[3], testData[7]);
    ASSERT_EQ(buffer_[4], testData[0]);
    ASSERT_EQ(buffer_[5], testData[1]);
    ASSERT_EQ(buffer_[6], testData[2]);
    ASSERT_EQ(buffer_[7], testData[3]);
    ASSERT_EQ(buffer_[8], resetValue_);
}

TEST_F(ReadableStringStreamTests, TestShortStream5) {
    ASSERT_EQ(buffer_[0], resetValue_);

    std::string testData = "12345678";
    rs::httpserver::ReadableStringStream stream(testData);
    ASSERT_EQ(stream.getLength(), 8);
    ASSERT_EQ(stream.getPosition(), 0);

    stream.AppendData("90123456");
    ASSERT_EQ(stream.getLength(), 16);
    ASSERT_EQ(stream.getPosition(), 0);

    // read the first N bytes of the available data at offset M
    int bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 16);
    ASSERT_EQ(stream.getLength(), 16);
    ASSERT_EQ(stream.getPosition(), 16);

    stream.AppendData("78901234");
    ASSERT_EQ(stream.getLength(), 24);
    ASSERT_EQ(stream.getPosition(), 16);

    bytesRead = stream.Read(buffer_, 0, sizeof(buffer_));
    ASSERT_EQ(bytesRead, 8);
    ASSERT_EQ(stream.getLength(), 24);
    ASSERT_EQ(stream.getPosition(), 24);
}

TEST_F(ReadableStringStreamTests, TestShortStream6) {
    rs::httpserver::ReadableStringStream stream("this is a placebo");

    bool thrown = false;
    try {
        stream.Write(buffer_, 0, sizeof(buffer_));
    } catch (const rs::httpserver::InvalidStreamOperationException& ex) {
        ASSERT_TRUE(SanityCheckWhatMessage(ex.what()));
        thrown = true;
    }

    ASSERT_TRUE(thrown);
}

TEST_F(ReadableStringStreamTests, TestShortStream7) {
    rs::httpserver::ReadableStringStream stream("");
    stream.Flush();
    ASSERT_TRUE(true);
}<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSemaphoreTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <iostream>
#include "itkSemaphore.h"
#include "itkMultiThreader.h"

struct SemaphoreTestUserData
{
  itk::Semaphore::Pointer m_Sem;
  bool m_Flag;
};

ITK_THREAD_RETURN_TYPE print_message_function( void *ptr )
{
 int threadID = ( (itk::MultiThreader::ThreadInfoStruct *)(ptr) )->ThreadID;
 SemaphoreTestUserData *data = static_cast<SemaphoreTestUserData *>(
                      ( (itk::MultiThreader::ThreadInfoStruct *)(ptr) )->UserData );

 if (threadID == 0)
   {
   data->m_Flag = true;
   data->m_Sem->Up();  // unblock if thread 1 is waiting
   }
 else
   {
   data->m_Sem->Down();// block if thread 1 reaches here first
   data->m_Flag = false;
   }

  return ITK_THREAD_RETURN_VALUE;
}

int itkSemaphoreTest()
{

  SemaphoreTestUserData sem;
  sem.m_Sem = itk::Semaphore::New();
  sem.m_Flag = false;

  try
    {
    sem.m_Sem->Initialize(0);
    itk::MultiThreader::Pointer multithreader = itk::MultiThreader::New();
    multithreader->SetNumberOfThreads(2);
    multithreader->SetSingleMethod( print_message_function, &sem);

    for (unsigned int i = 0; i < 2000; i++)
      {
      multithreader->SingleMethodExecute();
      if ( sem.m_Flag == true ) // flag should always be false
        {
        std::cerr << "[TEST FAILED]" << std::endl;
        return 1;
        }
      }

    sem.m_Sem->Remove();
    }
  catch (itk::ExceptionObject &e)
    {
    std::cerr << e << std::endl;
    return 2;
    }

  std::cout << "[TEST PASSED]" << std::endl;
  return EXIT_SUCCESS;
}
<commit_msg>ERR: Wrong function signature for itkSemaphoreTest function.<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkSemaphoreTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 2002 Insight Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#include <iostream>
#include "itkSemaphore.h"
#include "itkMultiThreader.h"

struct SemaphoreTestUserData
{
  itk::Semaphore::Pointer m_Sem;
  bool m_Flag;
};

ITK_THREAD_RETURN_TYPE print_message_function( void *ptr )
{
 int threadID = ( (itk::MultiThreader::ThreadInfoStruct *)(ptr) )->ThreadID;
 SemaphoreTestUserData *data = static_cast<SemaphoreTestUserData *>(
                      ( (itk::MultiThreader::ThreadInfoStruct *)(ptr) )->UserData );

 if (threadID == 0)
   {
   data->m_Flag = true;
   data->m_Sem->Up();  // unblock if thread 1 is waiting
   }
 else
   {
   data->m_Sem->Down();// block if thread 1 reaches here first
   data->m_Flag = false;
   }

  return ITK_THREAD_RETURN_VALUE;
}

int itkSemaphoreTest(int, char**)
{

  SemaphoreTestUserData sem;
  sem.m_Sem = itk::Semaphore::New();
  sem.m_Flag = false;

  try
    {
    sem.m_Sem->Initialize(0);
    itk::MultiThreader::Pointer multithreader = itk::MultiThreader::New();
    multithreader->SetNumberOfThreads(2);
    multithreader->SetSingleMethod( print_message_function, &sem);

    for (unsigned int i = 0; i < 2000; i++)
      {
      multithreader->SingleMethodExecute();
      if ( sem.m_Flag == true ) // flag should always be false
        {
        std::cerr << "[TEST FAILED]" << std::endl;
        return 1;
        }
      }

    sem.m_Sem->Remove();
    }
  catch (itk::ExceptionObject &e)
    {
    std::cerr << e << std::endl;
    return 2;
    }

  std::cout << "[TEST PASSED]" << std::endl;
  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (c) 2014, Cloudera, inc.
// Confidential Cloudera Information: Covered by NDA.

#include <gtest/gtest.h>
#include <boost/assign/list_of.hpp>

#include "kudu/client/client.h"
#include "kudu/integration-tests/mini_cluster.h"
#include "kudu/master/mini_master.h"
#include "kudu/tools/data_gen_util.h"
#include "kudu/tools/ksck_remote.h"
#include "kudu/util/monotime.h"
#include "kudu/util/random.h"
#include "kudu/util/test_util.h"

DECLARE_int32(heartbeat_interval_ms);

namespace kudu {
namespace tools {

using client::KuduColumnSchema;
using client::KuduInsert;
using client::KuduSession;
using client::KuduTable;
using client::KuduTableCreator;
using std::tr1::static_pointer_cast;
using std::tr1::shared_ptr;
using std::vector;
using std::string;

static const char *kTableName = "ksck-test-table";

class RemoteKsckTest : public KuduTest {
 public:
  RemoteKsckTest()
      : schema_(boost::assign::list_of
                (KuduColumnSchema("key", KuduColumnSchema::INT32))
                (KuduColumnSchema("int_val", KuduColumnSchema::INT32)),
                1),
        random_(SeedRandom()) {
  }

  virtual void SetUp() OVERRIDE {
    KuduTest::SetUp();

    // Speed up testing, saves about 700ms per TEST_F.
    FLAGS_heartbeat_interval_ms = 10;

    MiniClusterOptions opts;
    opts.num_tablet_servers = 3;
    mini_cluster_.reset(new MiniCluster(env_.get(), opts));
    ASSERT_OK(mini_cluster_->Start());

    master_rpc_addr_ = mini_cluster_->mini_master()->bound_rpc_addr();

    // Connect to the cluster.
    ASSERT_OK(client::KuduClientBuilder()
                     .add_master_server_addr(master_rpc_addr_.ToString())
                     .Build(&client_));

    // Create one table.
    gscoped_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
    ASSERT_OK(table_creator->table_name(kTableName)
                     .schema(&schema_)
                     .num_replicas(3)
                     .split_keys(GenerateSplitKeys())
                     .Create());
    // Make sure we can open the table.
    ASSERT_OK(client_->OpenTable(kTableName, &client_table_));

    ASSERT_OK(RemoteKsckMaster::Build(master_rpc_addr_, &master_));
    cluster_.reset(new KsckCluster(master_));
    ksck_.reset(new Ksck(cluster_));
  }

  virtual void TearDown() OVERRIDE {
    if (mini_cluster_) {
      mini_cluster_->Shutdown();
      mini_cluster_.reset();
    }
    KuduTest::TearDown();
  }

  // Writes rows to the table until the continue_writing flag is set to false.
  //
  // Public for use with boost::bind.
  void GenerateRowWritesLoop(CountDownLatch* started_writing,
                             const AtomicBool& continue_writing,
                             Promise<Status>* promise) {
    shared_ptr<KuduTable> table;
    Status status;
    status = client_->OpenTable(kTableName, &table);
    if (!status.ok()) {
      promise->Set(status);
    }
    shared_ptr<KuduSession> session(client_->NewSession());
    session->SetTimeoutMillis(10000);
    status = session->SetFlushMode(KuduSession::MANUAL_FLUSH);
    if (!status.ok()) {
      promise->Set(status);
    }

    for (uint64_t i = 0; continue_writing.Load(); i++) {
      gscoped_ptr<KuduInsert> insert(table->NewInsert());
      GenerateDataForRow(table->schema(), i, &random_, insert->mutable_row());
      status = session->Apply(insert.release());
      if (!status.ok()) {
        promise->Set(status);
      }
      status = session->Flush();
      if (!status.ok()) {
        promise->Set(status);
      }
      started_writing->CountDown(1);
    }
    promise->Set(Status::OK());
  }

 protected:
  // Generate a set of split keys for tablets used in this test.
  vector<string> GenerateSplitKeys() {
    vector<string> keys;
    vector<int> split_nums = boost::assign::list_of(33)(66);
    BOOST_FOREACH(int i, split_nums) {
      gscoped_ptr<KuduPartialRow> key(schema_.NewRow());
      CHECK_OK(key->SetInt32(0, i));
      keys.push_back(key->ToEncodedRowKeyOrDie());
    }
    return keys;
  }

  Status GenerateRowWrites(uint64_t num_rows) {
    shared_ptr<KuduTable> table;
    RETURN_NOT_OK(client_->OpenTable(kTableName, &table));
    shared_ptr<KuduSession> session(client_->NewSession());
    session->SetTimeoutMillis(10000);
    RETURN_NOT_OK(session->SetFlushMode(KuduSession::MANUAL_FLUSH));
    for (uint64_t i = 0; i < num_rows; i++) {
      VLOG(1) << "Generating write for row id " << i;
      gscoped_ptr<KuduInsert> insert(table->NewInsert());
      GenerateDataForRow(table->schema(), i, &random_, insert->mutable_row());
      RETURN_NOT_OK(session->Apply(insert.release()));
    }
    RETURN_NOT_OK(session->Flush());
    return Status::OK();
  }

  shared_ptr<Ksck> ksck_;
  shared_ptr<client::KuduClient> client_;

 private:
  Sockaddr master_rpc_addr_;
  shared_ptr<MiniCluster> mini_cluster_;
  client::KuduSchema schema_;
  shared_ptr<client::KuduTable> client_table_;
  shared_ptr<KsckMaster> master_;
  shared_ptr<KsckCluster> cluster_;
  Random random_;
};

TEST_F(RemoteKsckTest, TestMasterOk) {
  ASSERT_OK(ksck_->CheckMasterRunning());
}

TEST_F(RemoteKsckTest, TestTabletServersOk) {
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->CheckTabletServersRunning());
}

TEST_F(RemoteKsckTest, TestTableConsistency) {
  Status s;
  // We may have to sleep and loop because it takes some time for the
  // tablet leader to be elected and report back to the Master.
  for (int i = 1; i <= 10; i++) {
    LOG(INFO) << "Consistency check attempt " << i << "...";
    SleepFor(MonoDelta::FromMilliseconds(700));
    ASSERT_OK(ksck_->FetchTableAndTabletInfo());
    s = ksck_->CheckTablesConsistency();
    if (s.ok()) break;
  }
  ASSERT_OK(s);
}

TEST_F(RemoteKsckTest, TestChecksum) {
  uint64_t num_writes = 100;
  LOG(INFO) << "Generating row writes...";
  ASSERT_OK(GenerateRowWrites(num_writes));
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  Status s;
  // We may have to sleep and loop because it may take a little while for all
  // followers to sync up with the leader.
  for (int i = 1; i <= 10; i++) {
    LOG(INFO) << "Checksum attempt " << i << "...";
    SleepFor(MonoDelta::FromMilliseconds(700));
    s = ksck_->ChecksumData(vector<string>(),
                            vector<string>(),
                            ChecksumOptions(MonoDelta::FromSeconds(1), 16, false, 0));
    if (s.ok()) break;
  }
  ASSERT_OK(s);
}

TEST_F(RemoteKsckTest, TestChecksumTimeout) {
  uint64_t num_writes = 100;
  LOG(INFO) << "Generating row writes...";
  ASSERT_OK(GenerateRowWrites(num_writes));
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  // Use an impossibly low timeout value of zero!
  Status s = ksck_->ChecksumData(vector<string>(),
                                 vector<string>(),
                                 ChecksumOptions(MonoDelta::FromNanoseconds(0), 16, false, 0));
  ASSERT_TRUE(s.IsTimedOut()) << "Expected TimedOut Status, got: " << s.ToString();
}

TEST_F(RemoteKsckTest, TestChecksumSnapshot) {
  CountDownLatch started_writing(1);
  AtomicBool continue_writing(true);
  Promise<Status> promise;
  scoped_refptr<Thread> writer_thread;

  Thread::Create("RemoteKsckTest", "TestChecksumSnapshot",
                 &RemoteKsckTest::GenerateRowWritesLoop, this,
                 &started_writing, boost::cref(continue_writing), &promise,
                 &writer_thread);
  CHECK(started_writing.WaitFor(MonoDelta::FromSeconds(1)));

  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->ChecksumData(vector<string>(), vector<string>(),
                                ChecksumOptions(MonoDelta::FromSeconds(10), 16, true,
                                                client_->GetLatestObservedTimestamp())));
  continue_writing.Store(false);
  ASSERT_OK(promise.Get());
  writer_thread->Join();
}

TEST_F(RemoteKsckTest, TestChecksumSnapshotCurrentTimestamp) {
  CountDownLatch started_writing(1);
  AtomicBool continue_writing(true);
  Promise<Status> promise;
  scoped_refptr<Thread> writer_thread;

  Thread::Create("RemoteKsckTest", "TestChecksumSnapshot",
                 &RemoteKsckTest::GenerateRowWritesLoop, this,
                 &started_writing, boost::cref(continue_writing), &promise,
                 &writer_thread);
  CHECK(started_writing.WaitFor(MonoDelta::FromSeconds(1)));

  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->ChecksumData(vector<string>(), vector<string>(),
                                ChecksumOptions(MonoDelta::FromSeconds(10), 16, true,
                                                ChecksumOptions::kCurrentTimestamp)));
  continue_writing.Store(false);
  ASSERT_OK(promise.Get());
  writer_thread->Join();
}

} // namespace tools
} // namespace kudu
<commit_msg>Increase start timeout for ksck_remote-test<commit_after>// Copyright (c) 2014, Cloudera, inc.
// Confidential Cloudera Information: Covered by NDA.

#include <gtest/gtest.h>
#include <boost/assign/list_of.hpp>

#include "kudu/client/client.h"
#include "kudu/integration-tests/mini_cluster.h"
#include "kudu/master/mini_master.h"
#include "kudu/tools/data_gen_util.h"
#include "kudu/tools/ksck_remote.h"
#include "kudu/util/monotime.h"
#include "kudu/util/random.h"
#include "kudu/util/test_util.h"

DECLARE_int32(heartbeat_interval_ms);

namespace kudu {
namespace tools {

using client::KuduColumnSchema;
using client::KuduInsert;
using client::KuduSession;
using client::KuduTable;
using client::KuduTableCreator;
using std::tr1::static_pointer_cast;
using std::tr1::shared_ptr;
using std::vector;
using std::string;

static const char *kTableName = "ksck-test-table";

class RemoteKsckTest : public KuduTest {
 public:
  RemoteKsckTest()
      : schema_(boost::assign::list_of
                (KuduColumnSchema("key", KuduColumnSchema::INT32))
                (KuduColumnSchema("int_val", KuduColumnSchema::INT32)),
                1),
        random_(SeedRandom()) {
  }

  virtual void SetUp() OVERRIDE {
    KuduTest::SetUp();

    // Speed up testing, saves about 700ms per TEST_F.
    FLAGS_heartbeat_interval_ms = 10;

    MiniClusterOptions opts;
    opts.num_tablet_servers = 3;
    mini_cluster_.reset(new MiniCluster(env_.get(), opts));
    ASSERT_OK(mini_cluster_->Start());

    master_rpc_addr_ = mini_cluster_->mini_master()->bound_rpc_addr();

    // Connect to the cluster.
    ASSERT_OK(client::KuduClientBuilder()
                     .add_master_server_addr(master_rpc_addr_.ToString())
                     .Build(&client_));

    // Create one table.
    gscoped_ptr<KuduTableCreator> table_creator(client_->NewTableCreator());
    ASSERT_OK(table_creator->table_name(kTableName)
                     .schema(&schema_)
                     .num_replicas(3)
                     .split_keys(GenerateSplitKeys())
                     .Create());
    // Make sure we can open the table.
    ASSERT_OK(client_->OpenTable(kTableName, &client_table_));

    ASSERT_OK(RemoteKsckMaster::Build(master_rpc_addr_, &master_));
    cluster_.reset(new KsckCluster(master_));
    ksck_.reset(new Ksck(cluster_));
  }

  virtual void TearDown() OVERRIDE {
    if (mini_cluster_) {
      mini_cluster_->Shutdown();
      mini_cluster_.reset();
    }
    KuduTest::TearDown();
  }

  // Writes rows to the table until the continue_writing flag is set to false.
  //
  // Public for use with boost::bind.
  void GenerateRowWritesLoop(CountDownLatch* started_writing,
                             const AtomicBool& continue_writing,
                             Promise<Status>* promise) {
    shared_ptr<KuduTable> table;
    Status status;
    status = client_->OpenTable(kTableName, &table);
    if (!status.ok()) {
      promise->Set(status);
    }
    shared_ptr<KuduSession> session(client_->NewSession());
    session->SetTimeoutMillis(10000);
    status = session->SetFlushMode(KuduSession::MANUAL_FLUSH);
    if (!status.ok()) {
      promise->Set(status);
    }

    for (uint64_t i = 0; continue_writing.Load(); i++) {
      gscoped_ptr<KuduInsert> insert(table->NewInsert());
      GenerateDataForRow(table->schema(), i, &random_, insert->mutable_row());
      status = session->Apply(insert.release());
      if (!status.ok()) {
        promise->Set(status);
      }
      status = session->Flush();
      if (!status.ok()) {
        promise->Set(status);
      }
      started_writing->CountDown(1);
    }
    promise->Set(Status::OK());
  }

 protected:
  // Generate a set of split keys for tablets used in this test.
  vector<string> GenerateSplitKeys() {
    vector<string> keys;
    vector<int> split_nums = boost::assign::list_of(33)(66);
    BOOST_FOREACH(int i, split_nums) {
      gscoped_ptr<KuduPartialRow> key(schema_.NewRow());
      CHECK_OK(key->SetInt32(0, i));
      keys.push_back(key->ToEncodedRowKeyOrDie());
    }
    return keys;
  }

  Status GenerateRowWrites(uint64_t num_rows) {
    shared_ptr<KuduTable> table;
    RETURN_NOT_OK(client_->OpenTable(kTableName, &table));
    shared_ptr<KuduSession> session(client_->NewSession());
    session->SetTimeoutMillis(10000);
    RETURN_NOT_OK(session->SetFlushMode(KuduSession::MANUAL_FLUSH));
    for (uint64_t i = 0; i < num_rows; i++) {
      VLOG(1) << "Generating write for row id " << i;
      gscoped_ptr<KuduInsert> insert(table->NewInsert());
      GenerateDataForRow(table->schema(), i, &random_, insert->mutable_row());
      RETURN_NOT_OK(session->Apply(insert.release()));
    }
    RETURN_NOT_OK(session->Flush());
    return Status::OK();
  }

  shared_ptr<Ksck> ksck_;
  shared_ptr<client::KuduClient> client_;

 private:
  Sockaddr master_rpc_addr_;
  shared_ptr<MiniCluster> mini_cluster_;
  client::KuduSchema schema_;
  shared_ptr<client::KuduTable> client_table_;
  shared_ptr<KsckMaster> master_;
  shared_ptr<KsckCluster> cluster_;
  Random random_;
};

TEST_F(RemoteKsckTest, TestMasterOk) {
  ASSERT_OK(ksck_->CheckMasterRunning());
}

TEST_F(RemoteKsckTest, TestTabletServersOk) {
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->CheckTabletServersRunning());
}

TEST_F(RemoteKsckTest, TestTableConsistency) {
  Status s;
  // We may have to sleep and loop because it takes some time for the
  // tablet leader to be elected and report back to the Master.
  for (int i = 1; i <= 10; i++) {
    LOG(INFO) << "Consistency check attempt " << i << "...";
    SleepFor(MonoDelta::FromMilliseconds(700));
    ASSERT_OK(ksck_->FetchTableAndTabletInfo());
    s = ksck_->CheckTablesConsistency();
    if (s.ok()) break;
  }
  ASSERT_OK(s);
}

TEST_F(RemoteKsckTest, TestChecksum) {
  uint64_t num_writes = 100;
  LOG(INFO) << "Generating row writes...";
  ASSERT_OK(GenerateRowWrites(num_writes));
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  Status s;
  // We may have to sleep and loop because it may take a little while for all
  // followers to sync up with the leader.
  for (int i = 1; i <= 10; i++) {
    LOG(INFO) << "Checksum attempt " << i << "...";
    SleepFor(MonoDelta::FromMilliseconds(700));
    s = ksck_->ChecksumData(vector<string>(),
                            vector<string>(),
                            ChecksumOptions(MonoDelta::FromSeconds(1), 16, false, 0));
    if (s.ok()) break;
  }
  ASSERT_OK(s);
}

TEST_F(RemoteKsckTest, TestChecksumTimeout) {
  uint64_t num_writes = 100;
  LOG(INFO) << "Generating row writes...";
  ASSERT_OK(GenerateRowWrites(num_writes));
  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  // Use an impossibly low timeout value of zero!
  Status s = ksck_->ChecksumData(vector<string>(),
                                 vector<string>(),
                                 ChecksumOptions(MonoDelta::FromNanoseconds(0), 16, false, 0));
  ASSERT_TRUE(s.IsTimedOut()) << "Expected TimedOut Status, got: " << s.ToString();
}

TEST_F(RemoteKsckTest, TestChecksumSnapshot) {
  CountDownLatch started_writing(1);
  AtomicBool continue_writing(true);
  Promise<Status> promise;
  scoped_refptr<Thread> writer_thread;

  Thread::Create("RemoteKsckTest", "TestChecksumSnapshot",
                 &RemoteKsckTest::GenerateRowWritesLoop, this,
                 &started_writing, boost::cref(continue_writing), &promise,
                 &writer_thread);
  CHECK(started_writing.WaitFor(MonoDelta::FromSeconds(30)));

  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->ChecksumData(vector<string>(), vector<string>(),
                                ChecksumOptions(MonoDelta::FromSeconds(10), 16, true,
                                                client_->GetLatestObservedTimestamp())));
  continue_writing.Store(false);
  ASSERT_OK(promise.Get());
  writer_thread->Join();
}

TEST_F(RemoteKsckTest, TestChecksumSnapshotCurrentTimestamp) {
  CountDownLatch started_writing(1);
  AtomicBool continue_writing(true);
  Promise<Status> promise;
  scoped_refptr<Thread> writer_thread;

  Thread::Create("RemoteKsckTest", "TestChecksumSnapshot",
                 &RemoteKsckTest::GenerateRowWritesLoop, this,
                 &started_writing, boost::cref(continue_writing), &promise,
                 &writer_thread);
  CHECK(started_writing.WaitFor(MonoDelta::FromSeconds(30)));

  ASSERT_OK(ksck_->FetchTableAndTabletInfo());
  ASSERT_OK(ksck_->ChecksumData(vector<string>(), vector<string>(),
                                ChecksumOptions(MonoDelta::FromSeconds(10), 16, true,
                                                ChecksumOptions::kCurrentTimestamp)));
  continue_writing.Store(false);
  ASSERT_OK(promise.Get());
  writer_thread->Join();
}

} // namespace tools
} // namespace kudu
<|endoftext|>


<commit_before>/**
 * \file
 * \brief StaticRawMessageQueue and StaticRawMessageQueue2 classes header
 *
 * \author Copyright (C) 2015-2017 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
#define INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_

#include "distortos/RawMessageQueue.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

namespace distortos
{

/**
 * \brief StaticRawMessageQueue2 class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * This class is a replacement for StaticRawMessageQueue and StaticRawMessageQueueFromSize. To use this new API modify
 * your code in following way:
 * - `'StaticRawMessageQueue<T, QueueSize>'` -> `'StaticRawMessageQueue2<sizeof(T), QueueSize>'`;
 * - `'StaticRawMessageQueueFromSize<ElementSize, QueueSize>'` -> `'StaticRawMessageQueue2<ElementSize, QueueSize>'`;
 *
 * Transition schedule:
 * 1. v0.5.0 - `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>` are
 * converted to deprecated aliases to `StaticRawMessageQueue2<ElementSize, QueueSize>`;
 * 2. v0.6.0 - "old" `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>`
 * aliases are removed, `StaticRawMessageQueue2<ElementSize, QueueSize>` is renamed to
 * `StaticRawMessageQueue<ElementSize, QueueSize>`, deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is
 * added;
 * 3. v0.7.0 - deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is removed;
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<size_t ElementSize, size_t QueueSize>
class StaticRawMessageQueue2 : public RawMessageQueue
{
public:

	/**
	 * \brief StaticRawMessageQueue2's constructor
	 */

	explicit StaticRawMessageQueue2() :
			RawMessageQueue{{entryStorage_.data(), internal::dummyDeleter<EntryStorage>},
					{valueStorage_.data(), internal::dummyDeleter<uint8_t>}, ElementSize, QueueSize}
	{

	}

private:

	/// storage for queue's entries
	std::array<EntryStorage, QueueSize> entryStorage_;

	/// storage for queue's contents
	std::array<uint8_t, ElementSize * QueueSize> valueStorage_;
};

/**
 * \brief StaticRawMessageQueue class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * \deprecated scheduled to be removed after v0.5.0, use `StaticRawMessageQueue2<sizeof(T), QueueSize>`
 *
 * \tparam T is the type of data in queue
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<typename T, size_t QueueSize>
using StaticRawMessageQueue __attribute__ ((deprecated("Use StaticRawMessageQueue2<sizeof(T), QueueSize>"))) =
		StaticRawMessageQueue2<sizeof(T), QueueSize>;

/**
 * \brief StaticRawMessageQueueFromSize type alias is a variant of StaticRawMessageQueue which uses size of element
 * (instead of type) as template argument.
 *
 * \deprecated scheduled to be removed after v0.5.0, use `StaticRawMessageQueue2<ElementSize, QueueSize>`
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 */

template<size_t ElementSize, size_t QueueSize>
using StaticRawMessageQueueFromSize __attribute__ ((deprecated("Use StaticRawMessageQueue2<ElementSize, QueueSize>"))) =
		StaticRawMessageQueue2<ElementSize, QueueSize>;

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
<commit_msg>Remove StaticRawMessageQueueFromSize<commit_after>/**
 * \file
 * \brief StaticRawMessageQueue and StaticRawMessageQueue2 classes header
 *
 * \author Copyright (C) 2015-2018 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#ifndef INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
#define INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_

#include "distortos/RawMessageQueue.hpp"

#include "distortos/internal/memory/dummyDeleter.hpp"

namespace distortos
{

/**
 * \brief StaticRawMessageQueue2 class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * This class is a replacement for StaticRawMessageQueue and StaticRawMessageQueueFromSize. To use this new API modify
 * your code in following way:
 * - `'StaticRawMessageQueue<T, QueueSize>'` -> `'StaticRawMessageQueue2<sizeof(T), QueueSize>'`;
 * - `'StaticRawMessageQueueFromSize<ElementSize, QueueSize>'` -> `'StaticRawMessageQueue2<ElementSize, QueueSize>'`;
 *
 * Transition schedule:
 * 1. v0.5.0 - `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>` are
 * converted to deprecated aliases to `StaticRawMessageQueue2<ElementSize, QueueSize>`;
 * 2. v0.6.0 - "old" `StaticRawMessageQueue<T, QueueSize>` and `StaticRawMessageQueueFromSize<ElementSize, QueueSize>`
 * aliases are removed, `StaticRawMessageQueue2<ElementSize, QueueSize>` is renamed to
 * `StaticRawMessageQueue<ElementSize, QueueSize>`, deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is
 * added;
 * 3. v0.7.0 - deprecated `StaticRawMessageQueue2<ElementSize, QueueSize>` alias is removed;
 *
 * \tparam ElementSize is the size of single queue element, bytes
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<size_t ElementSize, size_t QueueSize>
class StaticRawMessageQueue2 : public RawMessageQueue
{
public:

	/**
	 * \brief StaticRawMessageQueue2's constructor
	 */

	explicit StaticRawMessageQueue2() :
			RawMessageQueue{{entryStorage_.data(), internal::dummyDeleter<EntryStorage>},
					{valueStorage_.data(), internal::dummyDeleter<uint8_t>}, ElementSize, QueueSize}
	{

	}

private:

	/// storage for queue's entries
	std::array<EntryStorage, QueueSize> entryStorage_;

	/// storage for queue's contents
	std::array<uint8_t, ElementSize * QueueSize> valueStorage_;
};

/**
 * \brief StaticRawMessageQueue class is a variant of RawMessageQueue that has automatic storage for queue's contents.
 *
 * \deprecated scheduled to be removed after v0.5.0, use `StaticRawMessageQueue2<sizeof(T), QueueSize>`
 *
 * \tparam T is the type of data in queue
 * \tparam QueueSize is the maximum number of elements in queue
 *
 * \ingroup queues
 */

template<typename T, size_t QueueSize>
using StaticRawMessageQueue __attribute__ ((deprecated("Use StaticRawMessageQueue2<sizeof(T), QueueSize>"))) =
		StaticRawMessageQueue2<sizeof(T), QueueSize>;

}	// namespace distortos

#endif	// INCLUDE_DISTORTOS_STATICRAWMESSAGEQUEUE_HPP_
<|endoftext|>


<commit_before>#include <QFile>
#include <QSettings>
#include <QSignalSpy>
#include "models/md5-database/md5-database-sqlite.h"
#include "catch.h"
#include "raii-helpers.h"

TEST_CASE("Md5DatabaseSqlite")
{
	FileDeleter settingsDeleter("tests/resources/md5s.sqlite", true);

	QSettings settings("tests/resources/settings.ini", QSettings::IniFormat);
	{
		Md5DatabaseSqlite init("tests/resources/md5s.sqlite", &settings);
		init.add("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_1x1.png");
		init.add("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_200x200.png");
		init.add("ad0234829205b9033196ba818f7a872b", "tests/resources/image_1x1.png");
	}

	SECTION("The constructor should load all the MD5s in memory")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").count() == 2);
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").contains("tests/resources/image_1x1.png"));
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").contains("tests/resources/image_200x200.png"));
		REQUIRE(md5s.exists("ad0234829205b9033196ba818f7a872b") == QStringList("tests/resources/image_1x1.png"));
	}

	SECTION("It can count the number of entries")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
		REQUIRE(md5s.count() == 3);
	}

	SECTION("Can remove an MD5 using remove()")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
		md5s.remove("5a105e8b9d40e1329780d62ea2265d8a");
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").isEmpty());
	}

	SECTION("Can remove a single MD5 path using remove()")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
		md5s.remove("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_1x1.png");
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a") == QStringList("tests/resources/image_200x200.png"));
	}

	SECTION("action()")
	{
		SECTION("when 'keep deleted' is set to false")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
			settings.setValue("Save/md5Duplicates", "move");
			settings.setValue("Save/keepDeletedMd5", false);

			QPair<QString, QString> action;

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save")); // The MD5 is not found so the default is "save"
			REQUIRE(action.second == QString(""));

			md5s.add("new", "tests/resources/image_1x1.png");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("move"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			md5s.remove("new");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString(""));

			// Restore state
			settings.setValue("Save/md5Duplicates", "save");
		}

		SECTION("when 'keep deleted' is set to true")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
			settings.setValue("Save/md5Duplicates", "move");
			settings.setValue("Save/keepDeletedMd5", true);

			QPair<QString, QString> action;

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString(""));

			md5s.add("new", "NON_EXISTING_FILE");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save")); // You can't "move" a non-existing file
			REQUIRE(action.second == QString("NON_EXISTING_FILE"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/keepDeletedMd5", false);
		}

		SECTION("for files in the same directory")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
			md5s.add("new", "tests/resources/image_1x1.png");

			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "move");
			settings.setValue("Save/keepDeletedMd5", false);

			QPair<QString, QString> action;

			action = md5s.action("new", "tests/resources/different/different.png");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "tests/resources/same.png");
			REQUIRE(action.first == QString("move"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "save");
		}

		SECTION("prioritize actions for files in the same directory")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s.sqlite", &settings);
			md5s.add("new", "same_dir/image.png"); // Doesn't exist
			md5s.add("new", "tests/resources/image_1x1.png"); // Exists

			settings.setValue("Save/md5Duplicates", "copy");
			settings.setValue("Save/md5DuplicatesSameDir", "ignore");
			settings.setValue("Save/keepDeletedMd5", true);

			QPair<QString, QString> action;

			action = md5s.action("new", "tests/resources/different/different.png");
			REQUIRE(action.first == QString("copy")); // None exists in this directory, but there is elsewhere
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "tests/resources/same.png");
			REQUIRE(action.first == QString("ignore")); // One exists in the same directory
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "same_dir/same.png");
			REQUIRE(action.first == QString("ignore")); // One used to exist in the same directory
			REQUIRE(action.second == QString("same_dir/image.png"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "save");
		}
	}
}
<commit_msg>Rename MD5 test file that conflicts with the Profile MD5s<commit_after>#include <QFile>
#include <QSettings>
#include <QSignalSpy>
#include "models/md5-database/md5-database-sqlite.h"
#include "catch.h"
#include "raii-helpers.h"

TEST_CASE("Md5DatabaseSqlite")
{
	FileDeleter settingsDeleter("tests/resources/md5s-test.sqlite", true);

	QSettings settings("tests/resources/settings.ini", QSettings::IniFormat);
	{
		Md5DatabaseSqlite init("tests/resources/md5s-test.sqlite", &settings);
		init.add("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_1x1.png");
		init.add("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_200x200.png");
		init.add("ad0234829205b9033196ba818f7a872b", "tests/resources/image_1x1.png");
	}

	SECTION("The constructor should load all the MD5s in memory")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").count() == 2);
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").contains("tests/resources/image_1x1.png"));
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").contains("tests/resources/image_200x200.png"));
		REQUIRE(md5s.exists("ad0234829205b9033196ba818f7a872b") == QStringList("tests/resources/image_1x1.png"));
	}

	SECTION("It can count the number of entries")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
		REQUIRE(md5s.count() == 3);
	}

	SECTION("Can remove an MD5 using remove()")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
		md5s.remove("5a105e8b9d40e1329780d62ea2265d8a");
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a").isEmpty());
	}

	SECTION("Can remove a single MD5 path using remove()")
	{
		Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
		md5s.remove("5a105e8b9d40e1329780d62ea2265d8a", "tests/resources/image_1x1.png");
		REQUIRE(md5s.exists("5a105e8b9d40e1329780d62ea2265d8a") == QStringList("tests/resources/image_200x200.png"));
	}

	SECTION("action()")
	{
		SECTION("when 'keep deleted' is set to false")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
			settings.setValue("Save/md5Duplicates", "move");
			settings.setValue("Save/keepDeletedMd5", false);

			QPair<QString, QString> action;

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save")); // The MD5 is not found so the default is "save"
			REQUIRE(action.second == QString(""));

			md5s.add("new", "tests/resources/image_1x1.png");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("move"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			md5s.remove("new");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString(""));

			// Restore state
			settings.setValue("Save/md5Duplicates", "save");
		}

		SECTION("when 'keep deleted' is set to true")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
			settings.setValue("Save/md5Duplicates", "move");
			settings.setValue("Save/keepDeletedMd5", true);

			QPair<QString, QString> action;

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString(""));

			md5s.add("new", "NON_EXISTING_FILE");

			action = md5s.action("new", "");
			REQUIRE(action.first == QString("save")); // You can't "move" a non-existing file
			REQUIRE(action.second == QString("NON_EXISTING_FILE"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/keepDeletedMd5", false);
		}

		SECTION("for files in the same directory")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
			md5s.add("new", "tests/resources/image_1x1.png");

			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "move");
			settings.setValue("Save/keepDeletedMd5", false);

			QPair<QString, QString> action;

			action = md5s.action("new", "tests/resources/different/different.png");
			REQUIRE(action.first == QString("save"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "tests/resources/same.png");
			REQUIRE(action.first == QString("move"));
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "save");
		}

		SECTION("prioritize actions for files in the same directory")
		{
			Md5DatabaseSqlite md5s("tests/resources/md5s-test.sqlite", &settings);
			md5s.add("new", "same_dir/image.png"); // Doesn't exist
			md5s.add("new", "tests/resources/image_1x1.png"); // Exists

			settings.setValue("Save/md5Duplicates", "copy");
			settings.setValue("Save/md5DuplicatesSameDir", "ignore");
			settings.setValue("Save/keepDeletedMd5", true);

			QPair<QString, QString> action;

			action = md5s.action("new", "tests/resources/different/different.png");
			REQUIRE(action.first == QString("copy")); // None exists in this directory, but there is elsewhere
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "tests/resources/same.png");
			REQUIRE(action.first == QString("ignore")); // One exists in the same directory
			REQUIRE(action.second == QString("tests/resources/image_1x1.png"));

			action = md5s.action("new", "same_dir/same.png");
			REQUIRE(action.first == QString("ignore")); // One used to exist in the same directory
			REQUIRE(action.second == QString("same_dir/image.png"));

			// Restore state
			md5s.remove("new");
			settings.setValue("Save/md5Duplicates", "save");
			settings.setValue("Save/md5DuplicatesSameDir", "save");
		}
	}
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_PERFORMANCE_COUNTERS_HPP_INCLUDED
#define TORRENT_PERFORMANCE_COUNTERS_HPP_INCLUDED

#include <boost/cstdint.hpp>
#include <boost/atomic.hpp>
#include "libtorrent/config.hpp"

namespace libtorrent
{
	struct TORRENT_EXTRA_EXPORT counters
	{
		enum stats_counter_t
		{
			// the number of peers that were disconnected this
			// tick due to protocol error
			error_peers,
			disconnected_peers,
			eof_peers,
			connreset_peers,
			connrefused_peers,
			connaborted_peers,
			perm_peers,
			buffer_peers,
			unreachable_peers,
			broken_pipe_peers,
			addrinuse_peers,
			no_access_peers,
			invalid_arg_peers,
			aborted_peers,

			piece_requests,
			max_piece_requests,
			invalid_piece_requests,
			choked_piece_requests,
			cancelled_piece_requests,
			piece_rejects,
			error_incoming_peers,
			error_outgoing_peers,
			error_rc4_peers,
			error_encrypted_peers,
			error_tcp_peers,
			error_utp_peers,

			// the number of times the piece picker was
			// successfully invoked, split by the reason
			// it was invoked
			reject_piece_picks,
			unchoke_piece_picks,
			incoming_redundant_piece_picks,
			incoming_piece_picks,
			end_game_piece_picks,
			snubbed_piece_picks,
			interesting_piece_picks,
			hash_fail_piece_picks,

			// these counters indicate which parts
			// of the piece picker CPU is spent in
			piece_picker_partial_loops,
			piece_picker_suggest_loops,
			piece_picker_sequential_loops,
			piece_picker_reverse_rare_loops,
			piece_picker_rare_loops,
			piece_picker_rand_start_loops,
			piece_picker_rand_loops,
			piece_picker_busy_loops,

			// reasons to disconnect peers
			connect_timeouts,
			uninteresting_peers,
			timeout_peers,
			no_memory_peers,
			too_many_peers,
			transport_timeout_peers,
			num_banned_peers,
			banned_for_hash_failure,

			// connection attempts (not necessarily successful)
			connection_attempts,
			// the number of iterations over the peer list when finding
			// a connect candidate
			connection_attempt_loops,
			// successful incoming connections (not rejected for any reason)
			incoming_connections,

			// counts events where the network
			// thread wakes up
			on_read_counter,
			on_write_counter,
			on_tick_counter,
			on_lsd_counter,
			on_lsd_peer_counter,
			on_udp_counter,
			on_accept_counter,
			on_disk_queue_counter,
			on_disk_counter,

			torrent_evicted_counter,

			// bittorrent message counters
			// TODO: should keepalives be in here too?
			// how about dont-have, share-mode, upload-only
			num_incoming_choke,
			num_incoming_unchoke,
			num_incoming_interested,
			num_incoming_not_interested,
			num_incoming_have,
			num_incoming_bitfield,
			num_incoming_request,
			num_incoming_piece,
			num_incoming_cancel,
			num_incoming_dht_port,
			num_incoming_suggest,
			num_incoming_have_all,
			num_incoming_have_none,
			num_incoming_reject,
			num_incoming_allowed_fast,
			num_incoming_ext_handshake,
			num_incoming_pex,
			num_incoming_metadata,
			num_incoming_extended,

			num_outgoing_choke,
			num_outgoing_unchoke,
			num_outgoing_interested,
			num_outgoing_not_interested,
			num_outgoing_have,
			num_outgoing_bitfield,
			num_outgoing_request,
			num_outgoing_piece,
			num_outgoing_cancel,
			num_outgoing_dht_port,
			num_outgoing_suggest,
			num_outgoing_have_all,
			num_outgoing_have_none,
			num_outgoing_reject,
			num_outgoing_allowed_fast,
			num_outgoing_ext_handshake,
			num_outgoing_pex,
			num_outgoing_metadata,
			num_outgoing_extended,

			num_piece_passed,
			num_piece_failed,

			num_have_pieces,
			num_total_pieces_added,

			num_blocks_written,
			num_blocks_read,
			num_blocks_hashed,
			num_blocks_cache_hits,
			num_write_ops,
			num_read_ops,
			num_read_back,

			disk_read_time,
			disk_write_time,
			disk_hash_time,
			disk_job_time,

			waste_piece_timed_out,
			waste_piece_cancelled,
			waste_piece_unknown,
			waste_piece_seed,
			waste_piece_end_game,
			waste_piece_closing,

			sent_payload_bytes,
			sent_bytes,
			sent_ip_overhead_bytes,
			sent_tracker_bytes,
			recv_payload_bytes,
			recv_bytes,
			recv_ip_overhead_bytes,
			recv_tracker_bytes,

			recv_failed_bytes,
			recv_redundant_bytes,

			dht_messages_in,
			dht_messages_out,
			dht_messages_out_dropped,
			dht_bytes_in,
			dht_bytes_out,

			dht_ping_in,
			dht_ping_out,
			dht_find_node_in,
			dht_find_node_out,
			dht_get_peers_in,
			dht_get_peers_out,
			dht_announce_peer_in,
			dht_announce_peer_out,
			dht_get_in,
			dht_get_out,
			dht_put_in,
			dht_put_out,

			// uTP counters
			utp_packet_loss,
			utp_timeout,
			utp_packets_in,
			utp_packets_out,
			utp_fast_retransmit,
			utp_packet_resend,
			utp_samples_above_target,
			utp_samples_below_target,
			utp_payload_pkts_in,
			utp_payload_pkts_out,
			utp_invalid_pkts_in,
			utp_redundant_pkts_in,

			// the buffer sizes accepted by
			// socket send calls. The larger
			// the more efficient. The size is
			// 1 << n, where n is the number
			// at the end of the counter name

			// 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
			// 16384, 32768, 65536, 131072, 262144, 524288, 1048576
			socket_send_size3,
			socket_send_size4,
			socket_send_size5,
			socket_send_size6,
			socket_send_size7,
			socket_send_size8,
			socket_send_size9,
			socket_send_size10,
			socket_send_size11,
			socket_send_size12,
			socket_send_size13,
			socket_send_size14,
			socket_send_size15,
			socket_send_size16,
			socket_send_size17,
			socket_send_size18,
			socket_send_size19,
			socket_send_size20,

			// the buffer sizes returned by
			// socket recv calls. The larger
			// the more efficient. The size is
			// 1 << n, where n is the number
			// at the end of the counter name

			// 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
			// 16384, 32768, 65536, 131072, 262144, 524288, 1048576
			socket_recv_size3,
			socket_recv_size4,
			socket_recv_size5,
			socket_recv_size6,
			socket_recv_size7,
			socket_recv_size8,
			socket_recv_size9,
			socket_recv_size10,
			socket_recv_size11,
			socket_recv_size12,
			socket_recv_size13,
			socket_recv_size14,
			socket_recv_size15,
			socket_recv_size16,
			socket_recv_size17,
			socket_recv_size18,
			socket_recv_size19,
			socket_recv_size20,

			num_stats_counters
		};

		// it is important that all gauges have a higher index than counters.
		// This assumption is relied upon in other parts of the code
		enum stats_gauges_t
		{
			num_checking_torrents = num_stats_counters,
			num_stopped_torrents,
			// upload_only means finished
			num_upload_only_torrents,
			num_downloading_torrents,
			num_seeding_torrents,
			num_queued_seeding_torrents,
			num_queued_download_torrents,
			num_error_torrents,

			// the number of torrents that don't have the
			// IP filter applied to them.
			non_filter_torrents,

			// counters related to evicting torrents
			num_loaded_torrents,
			num_pinned_torrents,

			// these counter indices deliberatly
			// match the order of socket type IDs
			// defined in socket_type.hpp.
			num_tcp_peers,
			num_socks5_peers,
			num_http_proxy_peers,
			num_utp_peers,
			num_i2p_peers,
			num_ssl_peers,
			num_ssl_socks5_peers,
			num_ssl_http_proxy_peers,
			num_ssl_utp_peers,

			num_peers_half_open,
			num_peers_connected,
			num_peers_up_interested,
			num_peers_down_interested,
			num_peers_up_unchoked,
			num_peers_down_unchoked,
			num_peers_up_requests,
			num_peers_down_requests,
			num_peers_up_disk,
			num_peers_down_disk,
			num_peers_end_game,

			write_cache_blocks,
			read_cache_blocks,
			request_latency,
			pinned_blocks,
			disk_blocks_in_use,
			queued_disk_jobs,
			num_read_jobs,
			num_write_jobs,
			num_jobs,
			num_writing_threads,
			num_running_threads,
			blocked_disk_jobs,
			queued_write_bytes,
			num_unchoke_slots,

			arc_mru_size,
			arc_mru_ghost_size,
			arc_mfu_size,
			arc_mfu_ghost_size,
			arc_write_size,
			arc_volatile_size,

			dht_nodes,
			dht_node_cache,
			dht_torrents,
			dht_peers,
			dht_immutable_data,
			dht_mutable_data,
			dht_allocated_observers,

			has_incoming_connections,

			limiter_up_queue,
			limiter_down_queue,
			limiter_up_bytes,
			limiter_down_bytes,

			num_counters,
			num_gauge_counters = num_counters - num_stats_counters
		};

		counters();

		counters(counters const&);
		counters& operator=(counters const&);

		// returns the new value
		boost::int64_t inc_stats_counter(int c, boost::int64_t value = 1);
		boost::int64_t operator[](int i) const;

		void set_value(int c, boost::int64_t value);
		void blend_stats_counter(int c, boost::int64_t value, int ratio);

	private:

		// TODO: some space could be saved here by making gauges 32 bits
#if BOOST_ATOMIC_LLONG_LOCK_FREE == 2
		boost::atomic<boost::int64_t> m_stats_counter[num_counters];
#else
		// if the atomic type is't lock-free, use a single lock instead, for
		// the whole array
		mutex m_mutex;
		boost::int64_t m_stats_counter[num_counters];
#endif
	};
}

#endif

<commit_msg>comment<commit_after>/*

Copyright (c) 2013, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#ifndef TORRENT_PERFORMANCE_COUNTERS_HPP_INCLUDED
#define TORRENT_PERFORMANCE_COUNTERS_HPP_INCLUDED

#include <boost/cstdint.hpp>
#include <boost/atomic.hpp>
#include "libtorrent/config.hpp"

namespace libtorrent
{
	struct TORRENT_EXTRA_EXPORT counters
	{
		enum stats_counter_t
		{
			// the number of peers that were disconnected this
			// tick due to protocol error
			error_peers,
			disconnected_peers,
			eof_peers,
			connreset_peers,
			connrefused_peers,
			connaborted_peers,
			perm_peers,
			buffer_peers,
			unreachable_peers,
			broken_pipe_peers,
			addrinuse_peers,
			no_access_peers,
			invalid_arg_peers,
			aborted_peers,

			piece_requests,
			max_piece_requests,
			invalid_piece_requests,
			choked_piece_requests,
			cancelled_piece_requests,
			piece_rejects,
			error_incoming_peers,
			error_outgoing_peers,
			error_rc4_peers,
			error_encrypted_peers,
			error_tcp_peers,
			error_utp_peers,

			// the number of times the piece picker was
			// successfully invoked, split by the reason
			// it was invoked
			reject_piece_picks,
			unchoke_piece_picks,
			incoming_redundant_piece_picks,
			incoming_piece_picks,
			end_game_piece_picks,
			snubbed_piece_picks,
			interesting_piece_picks,
			hash_fail_piece_picks,

			// these counters indicate which parts
			// of the piece picker CPU is spent in
			piece_picker_partial_loops,
			piece_picker_suggest_loops,
			piece_picker_sequential_loops,
			piece_picker_reverse_rare_loops,
			piece_picker_rare_loops,
			piece_picker_rand_start_loops,
			piece_picker_rand_loops,
			piece_picker_busy_loops,

			// reasons to disconnect peers
			connect_timeouts,
			uninteresting_peers,
			timeout_peers,
			no_memory_peers,
			too_many_peers,
			transport_timeout_peers,
			num_banned_peers,
			banned_for_hash_failure,

			// connection attempts (not necessarily successful)
			connection_attempts,
			// the number of iterations over the peer list when finding
			// a connect candidate
			connection_attempt_loops,
			// successful incoming connections (not rejected for any reason)
			incoming_connections,

			// counts events where the network
			// thread wakes up
			on_read_counter,
			on_write_counter,
			on_tick_counter,
			on_lsd_counter,
			on_lsd_peer_counter,
			on_udp_counter,
			on_accept_counter,
			on_disk_queue_counter,
			on_disk_counter,

			torrent_evicted_counter,

			// bittorrent message counters
			// TODO: should keepalives be in here too?
			// how about dont-have, share-mode, upload-only
			num_incoming_choke,
			num_incoming_unchoke,
			num_incoming_interested,
			num_incoming_not_interested,
			num_incoming_have,
			num_incoming_bitfield,
			num_incoming_request,
			num_incoming_piece,
			num_incoming_cancel,
			num_incoming_dht_port,
			num_incoming_suggest,
			num_incoming_have_all,
			num_incoming_have_none,
			num_incoming_reject,
			num_incoming_allowed_fast,
			num_incoming_ext_handshake,
			num_incoming_pex,
			num_incoming_metadata,
			num_incoming_extended,

			num_outgoing_choke,
			num_outgoing_unchoke,
			num_outgoing_interested,
			num_outgoing_not_interested,
			num_outgoing_have,
			num_outgoing_bitfield,
			num_outgoing_request,
			num_outgoing_piece,
			num_outgoing_cancel,
			num_outgoing_dht_port,
			num_outgoing_suggest,
			num_outgoing_have_all,
			num_outgoing_have_none,
			num_outgoing_reject,
			num_outgoing_allowed_fast,
			num_outgoing_ext_handshake,
			num_outgoing_pex,
			num_outgoing_metadata,
			num_outgoing_extended,

			num_piece_passed,
			num_piece_failed,

			num_have_pieces,
			num_total_pieces_added,

			num_blocks_written,
			num_blocks_read,
			num_blocks_hashed,
			num_blocks_cache_hits,
			num_write_ops,
			num_read_ops,
			num_read_back,

			disk_read_time,
			disk_write_time,
			disk_hash_time,
			disk_job_time,

			waste_piece_timed_out,
			waste_piece_cancelled,
			waste_piece_unknown,
			waste_piece_seed,
			waste_piece_end_game,
			waste_piece_closing,

			sent_payload_bytes,
			sent_bytes,
			sent_ip_overhead_bytes,
			sent_tracker_bytes,
			recv_payload_bytes,
			recv_bytes,
			recv_ip_overhead_bytes,
			recv_tracker_bytes,

			recv_failed_bytes,
			recv_redundant_bytes,

			dht_messages_in,
			dht_messages_out,
			dht_messages_out_dropped,
			dht_bytes_in,
			dht_bytes_out,

			dht_ping_in,
			dht_ping_out,
			dht_find_node_in,
			dht_find_node_out,
			dht_get_peers_in,
			dht_get_peers_out,
			dht_announce_peer_in,
			dht_announce_peer_out,
			dht_get_in,
			dht_get_out,
			dht_put_in,
			dht_put_out,

			// uTP counters
			utp_packet_loss,
			utp_timeout,
			utp_packets_in,
			utp_packets_out,
			utp_fast_retransmit,
			utp_packet_resend,
			utp_samples_above_target,
			utp_samples_below_target,
			utp_payload_pkts_in,
			utp_payload_pkts_out,
			utp_invalid_pkts_in,
			utp_redundant_pkts_in,

			// the buffer sizes accepted by
			// socket send calls. The larger
			// the more efficient. The size is
			// 1 << n, where n is the number
			// at the end of the counter name

			// 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
			// 16384, 32768, 65536, 131072, 262144, 524288, 1048576
			socket_send_size3,
			socket_send_size4,
			socket_send_size5,
			socket_send_size6,
			socket_send_size7,
			socket_send_size8,
			socket_send_size9,
			socket_send_size10,
			socket_send_size11,
			socket_send_size12,
			socket_send_size13,
			socket_send_size14,
			socket_send_size15,
			socket_send_size16,
			socket_send_size17,
			socket_send_size18,
			socket_send_size19,
			socket_send_size20,

			// the buffer sizes returned by
			// socket recv calls. The larger
			// the more efficient. The size is
			// 1 << n, where n is the number
			// at the end of the counter name

			// 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
			// 16384, 32768, 65536, 131072, 262144, 524288, 1048576
			socket_recv_size3,
			socket_recv_size4,
			socket_recv_size5,
			socket_recv_size6,
			socket_recv_size7,
			socket_recv_size8,
			socket_recv_size9,
			socket_recv_size10,
			socket_recv_size11,
			socket_recv_size12,
			socket_recv_size13,
			socket_recv_size14,
			socket_recv_size15,
			socket_recv_size16,
			socket_recv_size17,
			socket_recv_size18,
			socket_recv_size19,
			socket_recv_size20,

			num_stats_counters
		};

		// it is important that all gauges have a higher index than counters.
		// This assumption is relied upon in other parts of the code
		enum stats_gauges_t
		{
			num_checking_torrents = num_stats_counters,
			num_stopped_torrents,
			// upload_only means finished
			num_upload_only_torrents,
			num_downloading_torrents,
			num_seeding_torrents,
			num_queued_seeding_torrents,
			num_queued_download_torrents,
			num_error_torrents,

			// the number of torrents that don't have the
			// IP filter applied to them.
			non_filter_torrents,

			// counters related to evicting torrents
			num_loaded_torrents,
			num_pinned_torrents,

			// these counter indices deliberatly
			// match the order of socket type IDs
			// defined in socket_type.hpp.
			num_tcp_peers,
			num_socks5_peers,
			num_http_proxy_peers,
			num_utp_peers,
			num_i2p_peers,
			num_ssl_peers,
			num_ssl_socks5_peers,
			num_ssl_http_proxy_peers,
			num_ssl_utp_peers,

			num_peers_half_open,
			num_peers_connected,
			num_peers_up_interested,
			num_peers_down_interested,
			num_peers_up_unchoked,
			num_peers_down_unchoked,
			num_peers_up_requests,
			num_peers_down_requests,
			num_peers_up_disk,
			num_peers_down_disk,
			num_peers_end_game,

			write_cache_blocks,
			read_cache_blocks,
			request_latency,
			pinned_blocks,
			disk_blocks_in_use,
			queued_disk_jobs,
			num_read_jobs,
			num_write_jobs,
			num_jobs,
			num_writing_threads,
			num_running_threads,
			blocked_disk_jobs,
			queued_write_bytes,
			num_unchoke_slots,

			arc_mru_size,
			arc_mru_ghost_size,
			arc_mfu_size,
			arc_mfu_ghost_size,
			arc_write_size,
			arc_volatile_size,

			dht_nodes,
			dht_node_cache,
			dht_torrents,
			dht_peers,
			dht_immutable_data,
			dht_mutable_data,
			dht_allocated_observers,

			has_incoming_connections,

			limiter_up_queue,
			limiter_down_queue,
			limiter_up_bytes,
			limiter_down_bytes,

			num_counters,
			num_gauge_counters = num_counters - num_stats_counters
		};

		counters();

		counters(counters const&);
		counters& operator=(counters const&);

		// returns the new value
		boost::int64_t inc_stats_counter(int c, boost::int64_t value = 1);
		boost::int64_t operator[](int i) const;

		void set_value(int c, boost::int64_t value);
		void blend_stats_counter(int c, boost::int64_t value, int ratio);

	private:

		// TODO: some space could be saved here by making gauges 32 bits
		// TODO: restore these to regular integers. Instead have one copy
		// of the counters per thread and collect them at convenient
		// synchronization points
#if BOOST_ATOMIC_LLONG_LOCK_FREE == 2
		boost::atomic<boost::int64_t> m_stats_counter[num_counters];
#else
		// if the atomic type is't lock-free, use a single lock instead, for
		// the whole array
		mutex m_mutex;
		boost::int64_t m_stats_counter[num_counters];
#endif
	};
}

#endif

<|endoftext|>