<commit_before>#include <map>

#include <pqxx/pqxx>

namespace pqxx
{
namespace test
{
class test_failure : public std::logic_error
{
  const std::string m_file;
  int m_line;

public:
  test_failure(
	const std::string &ffile,
	int fline,
	const std::string &desc);

  ~test_failure() noexcept;

  const std::string &file() const noexcept { return m_file; }
  int line() const noexcept { return m_line; }
};

/// Drop a table, if it exists.
void drop_table(transaction_base &, const std::string &table);

class base_test;
using test_map = std::map<std::string, base_test *>;

/// Register test (if given); return test_map.
const test_map &register_test(base_test *);

/// Base class for test cases.
class base_test
{
public:
  using testfunc = void (*)(transaction_base &);

  base_test(const std::string &tname, testfunc func);

  /// Overridable: run test case.
  virtual void run() =0;

  virtual ~base_test() =0;
  const std::string &name() const noexcept { return m_name; }
private:
  std::string m_name;
protected:
  testfunc m_func;
};

/// Runner class for libpqxx tests.  Sets up a connection and transaction.
template<typename CONNECTION=connection, typename TRANSACTION=work>
class test_case final : public base_test
{
public:
  // func takes connection and transaction as arguments.
  test_case(const std::string &tname, testfunc func) :
    base_test(tname, func)
  {
  }

  ~test_case() {}

  virtual void run() override
  {
    CONNECTION c;
    TRANSACTION t(c, name());
    m_func(t);
  }
};

// Register a function taking (connection_base &, transaction_base &) as a test.
#define PQXX_REGISTER_TEST(function) \
	namespace \
	{ \
	pqxx::test::test_case<> test(#function, function); \
	}

// Register a test function using given connection and transaction types.
#define PQXX_REGISTER_TEST_CT(function, connection_type, transaction_type) \
	namespace \
	{ \
	pqxx::test::test_case< connection_type, transaction_type > \
		test(#function, function); \
	}

// Register a test function using a given connection type (instead of the
// default "connection").
#define PQXX_REGISTER_TEST_C(function, connection_type) \
	PQXX_REGISTER_TEST_CT(function, connection_type, pqxx::work)

// Register a test function using a given transaction type (default is "work").
#define PQXX_REGISTER_TEST_T(function, transaction_type) \
	PQXX_REGISTER_TEST_CT(function, pqxx::connection, transaction_type)

// Register test function that takes a nullconnection and nontransaction.
#define PQXX_REGISTER_TEST_NODB(function) \
	PQXX_REGISTER_TEST_CT( \
		function, \
		pqxx::nullconnection, \
		pqxx::nontransaction)

// Unconditional test failure.
#define PQXX_CHECK_NOTREACHED(desc) \
	pqxx::test::check_notreached(__FILE__, __LINE__, (desc))
[[noreturn]] void check_notreached( \
	const char file[], \
	int line, \
	std::string desc);

// Verify that a condition is met, similar to assert()
#define PQXX_CHECK(condition, desc) \
	pqxx::test::check(__FILE__, __LINE__, (condition), #condition, (desc))
void check(
	const char file[],
	int line,
	bool condition,
	const char text[],
	std::string desc);

// Verify that variable has the expected value.
#define PQXX_CHECK_EQUAL(actual, expected, desc) \
	pqxx::test::check_equal( \
		__FILE__, \
		__LINE__, \
		(actual), \
		#actual, \
		(expected), \
		#expected, \
		(desc))
template<typename ACTUAL, typename EXPECTED>
inline void check_equal(
	const char file[],
	int line,
	ACTUAL actual,
	const char actual_text[],
	EXPECTED expected,
	const char expected_text[],
	std::string desc)
{
  if (expected == actual) return;
  const std::string fulldesc =
	desc + " (" + actual_text + " <> " + expected_text + ": "
	"actual=" + to_string(actual) + ", "
	"expected=" + to_string(expected) + ")";
  throw test_failure(file, line, fulldesc);
}

// Verify that two values are not equal.
#define PQXX_CHECK_NOT_EQUAL(value1, value2, desc) \
	pqxx::test::check_not_equal( \
		__FILE__, \
		__LINE__, \
		(value1), \
		#value1, \
		(value2), \
		#value2, \
		(desc))
template<typename VALUE1, typename VALUE2>
inline void check_not_equal(
	const char file[],
	int line,
	VALUE1 value1,
	const char text1[],
	VALUE2 value2,
	const char text2[],
	std::string desc)
{
  if (value1 != value2) return;
  const std::string fulldesc =
	desc + " (" + text1 + " == " + text2 + ": "
	"both are " + to_string(value2) + ")";
  throw test_failure(file, line, fulldesc);
}

// Verify that value1 is less than value2.
#define PQXX_CHECK_LESS(value1, value2, desc) \
	pqxx::test::check_less( \
		__FILE__, \
		__LINE__, \
		(value1), \
		#value1, \
		(value2), \
		#value2, \
		(desc))
template<typename VALUE1, typename VALUE2>
inline void check_less(
	const char file[],
	int line,
	VALUE1 value1,
	const char text1[],
	VALUE2 value2,
	const char text2[],
	std::string desc)
{
  if (value1 < value2) return;
  const std::string fulldesc =
	desc + " (" + text1 + " >= " + text2 + ": "
	"\"lower\"=" + to_string(value1) + ", "
	"\"upper\"=" + to_string(value2) + ")";
  throw test_failure(file, line, fulldesc);
}

struct failure_to_fail {};

namespace internal
{
/// Syntactic placeholder: require (and accept) semicolon after block.
inline void end_of_statement()
{
}
}

// Verify that "action" throws "exception_type."
#define PQXX_CHECK_THROWS(action, exception_type, desc) \
	{ \
	  try \
	  { \
	    action ; \
	    throw pqxx::test::failure_to_fail(); \
	  } \
	  catch (const pqxx::test::failure_to_fail &) \
	  { \
	    PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" did not throw " #exception_type ")"); \
	  } \
	  catch (const exception_type &) {} \
	  catch (...) \
	  { \
	    PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" " \
		"threw exception other than " #exception_type ")"); \
	  } \
	} \
        pqxx::test::internal::end_of_statement()

#define PQXX_CHECK_BOUNDS(value, lower, upper, desc) \
	pqxx::test::check_bounds( \
		__FILE__, \
		 __LINE__, \
		(value), \
		#value, \
		(lower), \
		#lower, \
		(upper), \
		#upper, \
		(desc))
template<typename VALUE, typename LOWER, typename UPPER>
inline void check_bounds(
	const char file[],
	int line,
	VALUE value,
	const char text[],
	LOWER lower,
	const char lower_text[],
	UPPER upper,
	const char upper_text[],
	const std::string &desc)
{
  const std::string
	range_check = std::string(lower_text) + " < " + upper_text,
	lower_check = std::string("!(") + text + " < " + lower_text + ")",
	upper_check = std::string(text) + " < " + upper_text;

  pqxx::test::check(
	file,
	line,
	lower < upper,
	range_check.c_str(),
	desc + " (acceptable range is empty; value was " + text + ")");
  pqxx::test::check(
	file,
	line,
	!(value < lower),
	lower_check.c_str(),
	desc + " (" + text + " is below lower bound " + lower_text + ")");
  pqxx::test::check(
	file,
	line,
	value < upper,
	upper_check.c_str(),
	desc + " (" + text + " is not below upper bound " + upper_text + ")");
}

// Report expected exception
void expected_exception(const std::string &);

// Represent result row as string
std::string list_row(row);
// Represent result as string
std::string list_result(result);
// Represent result iterator as string
std::string list_result_iterator(result::const_iterator);

// @deprecated Set up test data for legacy tests.
void create_pqxxevents(transaction_base &);
} // namespace test

// Support string conversion on result rows for debug output.
template<> struct string_traits<row>
{
  static const char *name() { return "pqxx::row"; }
  static bool has_null() { return false; }
  static bool is_null(row) { return false; }
  static result null(); // Not needed
  static void from_string(const char Str[], result &Obj); // Not needed
  static std::string to_string(row Obj)
	{ return pqxx::test::list_row(Obj); }
};

// Support string conversion on result objects for debug output.
template<> struct string_traits<result>
{
  static const char *name() { return "pqxx::result"; }
  static bool has_null() { return true; }
  static bool is_null(result r) { return r.empty(); }
  static result null() { return result(); }
  static void from_string(const char Str[], result &Obj); // Not needed
  static std::string to_string(result Obj)
	{ return pqxx::test::list_result(Obj); }
};

// Support string conversion on result::const_iterator for debug output.
template<> struct string_traits<result::const_iterator>
{
  using subject_type = result::const_iterator;
  static const char *name() { return "pqxx::result::const_iterator"; }
  static bool has_null() { return false; }
  static bool is_null(subject_type) { return false; }
  static result null(); // Not needed
  static void from_string(const char Str[], subject_type &Obj); // Not needed
  static std::string to_string(subject_type Obj)
	{ return pqxx::test::list_result_iterator(Obj); }
};

// Support string conversion on vector<string> for debug output.
template<> struct string_traits<std::vector<std::string>>
{
  using subject_type = std::vector<std::string>;
  static const char *name() { return "vector<string>"; }
  static bool has_null() { return false; }
  static bool is_null(subject_type) { return false; }
  static subject_type null(); // Not needed
  static void from_string(const char Str[], subject_type &Obj); // Not needed
  static std::string to_string(const subject_type &Obj)
	{ return separated_list("; ", Obj); }
};
} // namespace pqxx
<commit_msg>Missed a file in commit.<commit_after>#include <map>

#include <pqxx/pqxx>

namespace pqxx
{
namespace test
{
class test_failure : public std::logic_error
{
  const std::string m_file;
  int m_line;

public:
  test_failure(
	const std::string &ffile,
	int fline,
	const std::string &desc);

  ~test_failure() noexcept;

  const std::string &file() const noexcept { return m_file; }
  int line() const noexcept { return m_line; }
};

/// Drop a table, if it exists.
void drop_table(transaction_base &, const std::string &table);

class base_test;
using test_map = std::map<std::string, base_test *>;

/// Register test (if given); return test_map.
const test_map &register_test(base_test *);

/// Base class for test cases.
class base_test
{
public:
  using testfunc = void (*)(transaction_base &);

  base_test(const std::string &tname, testfunc func);

  /// Overridable: run test case.
  virtual void run() =0;

  virtual ~base_test() =0;
  const std::string &name() const noexcept { return m_name; }
private:
  std::string m_name;
protected:
  testfunc m_func;
};

/// Runner class for libpqxx tests.  Sets up a connection and transaction.
template<typename CONNECTION=connection, typename TRANSACTION=work>
class test_case final : public base_test
{
public:
  // func takes connection and transaction as arguments.
  test_case(const std::string &tname, testfunc func) :
    base_test(tname, func)
  {
  }

  ~test_case() {}

  virtual void run() override
  {
    CONNECTION c;
    TRANSACTION t(c, name());
    m_func(t);
  }
};

// Register a function taking (connection_base &, transaction_base &) as a test.
#define PQXX_REGISTER_TEST(function) \
	namespace \
	{ \
	pqxx::test::test_case<> test(#function, function); \
	}

// Register a test function using given connection and transaction types.
#define PQXX_REGISTER_TEST_CT(function, connection_type, transaction_type) \
	namespace \
	{ \
	pqxx::test::test_case< connection_type, transaction_type > \
		test(#function, function); \
	}

// Register a test function using a given connection type (instead of the
// default "connection").
#define PQXX_REGISTER_TEST_C(function, connection_type) \
	PQXX_REGISTER_TEST_CT(function, connection_type, pqxx::work)

// Register a test function using a given transaction type (default is "work").
#define PQXX_REGISTER_TEST_T(function, transaction_type) \
	PQXX_REGISTER_TEST_CT(function, pqxx::connection, transaction_type)

// Register test function that takes a nullconnection and nontransaction.
#define PQXX_REGISTER_TEST_NODB(function) \
	PQXX_REGISTER_TEST_CT( \
		function, \
		pqxx::nullconnection, \
		pqxx::nontransaction)

// Unconditional test failure.
#define PQXX_CHECK_NOTREACHED(desc) \
	pqxx::test::check_notreached(__FILE__, __LINE__, (desc))
[[noreturn]] void check_notreached( \
	const char file[], \
	int line, \
	std::string desc);

// Verify that a condition is met, similar to assert()
#define PQXX_CHECK(condition, desc) \
	pqxx::test::check(__FILE__, __LINE__, (condition), #condition, (desc))
void check(
	const char file[],
	int line,
	bool condition,
	const char text[],
	std::string desc);

// Verify that variable has the expected value.
#define PQXX_CHECK_EQUAL(actual, expected, desc) \
	pqxx::test::check_equal( \
		__FILE__, \
		__LINE__, \
		(actual), \
		#actual, \
		(expected), \
		#expected, \
		(desc))
template<typename ACTUAL, typename EXPECTED>
inline void check_equal(
	const char file[],
	int line,
	ACTUAL actual,
	const char actual_text[],
	EXPECTED expected,
	const char expected_text[],
	std::string desc)
{
  if (expected == actual) return;
  const std::string fulldesc =
	desc + " (" + actual_text + " <> " + expected_text + ": "
	"actual=" + to_string(actual) + ", "
	"expected=" + to_string(expected) + ")";
  throw test_failure(file, line, fulldesc);
}

// Verify that two values are not equal.
#define PQXX_CHECK_NOT_EQUAL(value1, value2, desc) \
	pqxx::test::check_not_equal( \
		__FILE__, \
		__LINE__, \
		(value1), \
		#value1, \
		(value2), \
		#value2, \
		(desc))
template<typename VALUE1, typename VALUE2>
inline void check_not_equal(
	const char file[],
	int line,
	VALUE1 value1,
	const char text1[],
	VALUE2 value2,
	const char text2[],
	std::string desc)
{
  if (value1 != value2) return;
  const std::string fulldesc =
	desc + " (" + text1 + " == " + text2 + ": "
	"both are " + to_string(value2) + ")";
  throw test_failure(file, line, fulldesc);
}

// Verify that value1 is less than value2.
#define PQXX_CHECK_LESS(value1, value2, desc) \
	pqxx::test::check_less( \
		__FILE__, \
		__LINE__, \
		(value1), \
		#value1, \
		(value2), \
		#value2, \
		(desc))
template<typename VALUE1, typename VALUE2>
inline void check_less(
	const char file[],
	int line,
	VALUE1 value1,
	const char text1[],
	VALUE2 value2,
	const char text2[],
	std::string desc)
{
  if (value1 < value2) return;
  const std::string fulldesc =
	desc + " (" + text1 + " >= " + text2 + ": "
	"\"lower\"=" + to_string(value1) + ", "
	"\"upper\"=" + to_string(value2) + ")";
  throw test_failure(file, line, fulldesc);
}

struct failure_to_fail {};

namespace internal
{
/// Syntactic placeholder: require (and accept) semicolon after block.
inline void end_of_statement()
{
}
}

// Verify that "action" throws an exception, of any std::exception-based type.
#define PQXX_CHECK_THROWS_EXCEPTION(action, desc) \
	{ \
	  try \
	  { \
	    action ; \
	    throw pqxx::test::failure_to_fail(); \
	  } \
	  catch (const pqxx::test::failure_to_fail &) \
	  { \
	    PQXX_CHECK_NOTREACHED( \
		std::string(desc) + " (\"" #action "\" did not throw)"); \
	  } \
	  catch (const std::exception &) {} \
          catch (...) \
          { \
            PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" threw non-exception type)"); \
          } \
	} \
        pqxx::test::internal::end_of_statement()

// Verify that "action" throws "exception_type" (which is not std::exception).
#define PQXX_CHECK_THROWS(action, exception_type, desc) \
	{ \
	  try \
	  { \
	    action ; \
	    throw pqxx::test::failure_to_fail(); \
	  } \
	  catch (const pqxx::test::failure_to_fail &) \
	  { \
	    PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" did not throw " #exception_type ")"); \
	  } \
	  catch (const exception_type &) {} \
	  catch (const std::exception &e) \
	  { \
	    PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" " \
		"threw exception other than " #exception_type ": " + \
                e.what() + ")"); \
	  } \
          catch (...) \
          { \
            PQXX_CHECK_NOTREACHED( \
		std::string(desc) + \
		" (\"" #action "\" threw non-exception type)"); \
          } \
	} \
        pqxx::test::internal::end_of_statement()

#define PQXX_CHECK_BOUNDS(value, lower, upper, desc) \
	pqxx::test::check_bounds( \
		__FILE__, \
		 __LINE__, \
		(value), \
		#value, \
		(lower), \
		#lower, \
		(upper), \
		#upper, \
		(desc))
template<typename VALUE, typename LOWER, typename UPPER>
inline void check_bounds(
	const char file[],
	int line,
	VALUE value,
	const char text[],
	LOWER lower,
	const char lower_text[],
	UPPER upper,
	const char upper_text[],
	const std::string &desc)
{
  const std::string
	range_check = std::string(lower_text) + " < " + upper_text,
	lower_check = std::string("!(") + text + " < " + lower_text + ")",
	upper_check = std::string(text) + " < " + upper_text;

  pqxx::test::check(
	file,
	line,
	lower < upper,
	range_check.c_str(),
	desc + " (acceptable range is empty; value was " + text + ")");
  pqxx::test::check(
	file,
	line,
	!(value < lower),
	lower_check.c_str(),
	desc + " (" + text + " is below lower bound " + lower_text + ")");
  pqxx::test::check(
	file,
	line,
	value < upper,
	upper_check.c_str(),
	desc + " (" + text + " is not below upper bound " + upper_text + ")");
}

// Report expected exception
void expected_exception(const std::string &);

// Represent result row as string
std::string list_row(row);
// Represent result as string
std::string list_result(result);
// Represent result iterator as string
std::string list_result_iterator(result::const_iterator);

// @deprecated Set up test data for legacy tests.
void create_pqxxevents(transaction_base &);
} // namespace test

// Support string conversion on result rows for debug output.
template<> struct string_traits<row>
{
  static const char *name() { return "pqxx::row"; }
  static bool has_null() { return false; }
  static bool is_null(row) { return false; }
  static result null(); // Not needed
  static void from_string(const char Str[], result &Obj); // Not needed
  static std::string to_string(row Obj)
	{ return pqxx::test::list_row(Obj); }
};

// Support string conversion on result objects for debug output.
template<> struct string_traits<result>
{
  static const char *name() { return "pqxx::result"; }
  static bool has_null() { return true; }
  static bool is_null(result r) { return r.empty(); }
  static result null() { return result(); }
  static void from_string(const char Str[], result &Obj); // Not needed
  static std::string to_string(result Obj)
	{ return pqxx::test::list_result(Obj); }
};

// Support string conversion on result::const_iterator for debug output.
template<> struct string_traits<result::const_iterator>
{
  using subject_type = result::const_iterator;
  static const char *name() { return "pqxx::result::const_iterator"; }
  static bool has_null() { return false; }
  static bool is_null(subject_type) { return false; }
  static result null(); // Not needed
  static void from_string(const char Str[], subject_type &Obj); // Not needed
  static std::string to_string(subject_type Obj)
	{ return pqxx::test::list_result_iterator(Obj); }
};

// Support string conversion on vector<string> for debug output.
template<> struct string_traits<std::vector<std::string>>
{
  using subject_type = std::vector<std::string>;
  static const char *name() { return "vector<string>"; }
  static bool has_null() { return false; }
  static bool is_null(subject_type) { return false; }
  static subject_type null(); // Not needed
  static void from_string(const char Str[], subject_type &Obj); // Not needed
  static std::string to_string(const subject_type &Obj)
	{ return separated_list("; ", Obj); }
};
} // namespace pqxx
<|endoftext|>


<commit_before>#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/aux_/session_impl.hpp"

#include <boost/utility.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/thread/mutex.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using namespace libtorrent;
using namespace boost::filesystem;

const int piece_size = 16;

void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
{
	std::cerr << "on_read_piece piece: " << j.piece << std::endl;
	TEST_CHECK(ret == size);
	TEST_CHECK(std::equal(j.buffer, j.buffer + ret, data));
}

void run_storage_tests(boost::intrusive_ptr<torrent_info> info
	, path const& test_path
	, libtorrent::storage_mode_t storage_mode)
{
	const int half = piece_size / 2;

	char piece0[piece_size] =
	{ 6, 6, 6, 6, 6, 6, 6, 6
	, 9, 9, 9, 9, 9, 9, 9, 9};

	char piece1[piece_size] =
	{ 0, 0, 0, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	char piece2[piece_size] =
	{ 0, 0, 1, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	info->set_hash(0, hasher(piece0, piece_size).final());
	info->set_hash(1, hasher(piece1, piece_size).final());
	info->set_hash(2, hasher(piece2, piece_size).final());

	info->create_torrent();

	create_directory(test_path / "temp_storage");

	int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
	TEST_CHECK(info->num_pieces() == num_pieces);

	char piece[piece_size];

	{ // avoid having two storages use the same files
	file_pool fp;
	boost::scoped_ptr<storage_interface> s(
		default_storage_constructor(info, test_path, fp));

	// write piece 1 (in slot 0)
	s->write(piece1, 0, 0, half);
	s->write(piece1 + half, 0, half, half);

	// verify piece 1
	TEST_CHECK(s->read(piece, 0, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece1));

	// do the same with piece 0 and 2 (in slot 1 and 2)
	s->write(piece0, 1, 0, piece_size);
	s->write(piece2, 2, 0, piece_size);

	// verify piece 0 and 2
	TEST_CHECK(s->read(piece, 1, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece0));

	s->read(piece, 2, 0, piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece2));

	s->release_files();
	}

	// make sure the piece_manager can identify the pieces
	{
	file_pool fp;
	disk_io_thread io;
	boost::shared_ptr<int> dummy(new int);
	boost::intrusive_ptr<piece_manager> pm = new piece_manager(dummy, info
		, test_path, fp, io, default_storage_constructor);
	boost::mutex lock;
	libtorrent::aux::piece_checker_data d;

	std::vector<bool> pieces;
	num_pieces = 0;
	TEST_CHECK(pm->check_fastresume(d, pieces, num_pieces
		, storage_mode) == false);
	bool finished = false;
	float progress;
	num_pieces = 0;
	boost::recursive_mutex mutex;
	while (!finished)
		boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex);

	TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
		, true));

	boost::function<void(int, disk_io_job const&)> none;
	TEST_CHECK(exists(test_path / "temp_storage"));
	pm->async_move_storage(test_path / "temp_storage2", none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage"));
	TEST_CHECK(exists(test_path / "temp_storage2/temp_storage"));
	pm->async_move_storage(test_path , none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage"));
	remove_all(test_path / "temp_storage2");

	peer_request r;
	r.piece = 0;
	r.start = 0;
	r.length = piece_size;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, piece_size));
	r.piece = 1;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size));
	r.piece = 2;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size));
	pm->async_release_files(none);

	}
}

void run_test(path const& test_path)
{
	std::cerr << "\n=== " << test_path << " ===\n" << std::endl;

	boost::intrusive_ptr<torrent_info> info(new torrent_info());
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17);
	info->add_file("temp_storage/test2.tmp", 612);
	info->add_file("temp_storage/test3.tmp", 0);
	info->add_file("temp_storage/test4.tmp", 0);
	info->add_file("temp_storage/test5.tmp", 1);

	std::cerr << "=== test 1 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// make sure the files have the correct size
	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17);
	std::cerr << file_size(test_path / "temp_storage" / "test2.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test2.tmp") == 31);
	TEST_CHECK(exists(test_path / "temp_storage/test3.tmp"));
	TEST_CHECK(exists(test_path / "temp_storage/test4.tmp"));
	remove_all(test_path / "temp_storage");

// ==============================================

	// make sure remap_files works
	std::vector<std::pair<std::string, libtorrent::size_type> > map;
	map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
	bool ret = info->remap_files(map);
	TEST_CHECK(ret);

	std::cerr << "=== test 2 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 48);

	remove_all(test_path / "temp_storage");

// ==============================================

	info = new torrent_info();
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17 + 612 + 1);

	std::cerr << "=== test 3 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// 48 = piece_size * 3
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
	remove_all(test_path / "temp_storage");

// ==============================================

	std::cerr << "=== test 4 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_allocate);

	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17 + 612 + 1);

	remove_all(test_path / "temp_storage");
}

int test_main()
{
	std::vector<path> test_paths;
	char* env = std::getenv("TORRENT_TEST_PATHS");
	if (env == 0)
	{
		test_paths.push_back(initial_path());
	}
	else
	{
		char* p = std::strtok(env, ";");
		while (p != 0)
		{
			test_paths.push_back(complete(p));
			p = std::strtok(0, ";");
		}
	}

	std::for_each(test_paths.begin(), test_paths.end(), bind(&run_test, _1));
	return 0;
}

<commit_msg>fixed test_storage<commit_after>#include "libtorrent/storage.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/hasher.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/aux_/session_impl.hpp"

#include <boost/utility.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/thread/mutex.hpp>

#include "test.hpp"
#include "setup_transfer.hpp"

using namespace libtorrent;
using namespace boost::filesystem;

const int piece_size = 16;

void on_read_piece(int ret, disk_io_job const& j, char const* data, int size)
{
	std::cerr << "on_read_piece piece: " << j.piece << std::endl;
	TEST_CHECK(ret == size);
	TEST_CHECK(std::equal(j.buffer, j.buffer + ret, data));
}

void run_storage_tests(boost::intrusive_ptr<torrent_info> info
	, path const& test_path
	, libtorrent::storage_mode_t storage_mode)
{
	const int half = piece_size / 2;

	char piece0[piece_size] =
	{ 6, 6, 6, 6, 6, 6, 6, 6
	, 9, 9, 9, 9, 9, 9, 9, 9};

	char piece1[piece_size] =
	{ 0, 0, 0, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	char piece2[piece_size] =
	{ 0, 0, 1, 0, 0, 0, 0, 0
	, 1, 1, 1, 1, 1, 1, 1, 1};

	info->set_hash(0, hasher(piece0, piece_size).final());
	info->set_hash(1, hasher(piece1, piece_size).final());
	info->set_hash(2, hasher(piece2, piece_size).final());

	info->create_torrent();

	create_directory(test_path / "temp_storage");

	int num_pieces = (1 + 612 + 17 + piece_size - 1) / piece_size;
	TEST_CHECK(info->num_pieces() == num_pieces);

	char piece[piece_size];

	{ // avoid having two storages use the same files
	file_pool fp;
	boost::scoped_ptr<storage_interface> s(
		default_storage_constructor(info, test_path, fp));

	// write piece 1 (in slot 0)
	s->write(piece1, 0, 0, half);
	s->write(piece1 + half, 0, half, half);

	// verify piece 1
	TEST_CHECK(s->read(piece, 0, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece1));

	// do the same with piece 0 and 2 (in slot 1 and 2)
	s->write(piece0, 1, 0, piece_size);
	s->write(piece2, 2, 0, piece_size);

	// verify piece 0 and 2
	TEST_CHECK(s->read(piece, 1, 0, piece_size) == piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece0));

	s->read(piece, 2, 0, piece_size);
	TEST_CHECK(std::equal(piece, piece + piece_size, piece2));

	s->release_files();
	}

	// make sure the piece_manager can identify the pieces
	{
	file_pool fp;
	disk_io_thread io;
	boost::shared_ptr<int> dummy(new int);
	boost::intrusive_ptr<piece_manager> pm = new piece_manager(dummy, info
		, test_path, fp, io, default_storage_constructor);
	boost::mutex lock;
	libtorrent::aux::piece_checker_data d;

	std::vector<bool> pieces;
	num_pieces = 0;
	std::string error_msg;
	TEST_CHECK(pm->check_fastresume(d, pieces, num_pieces
		, storage_mode, error_msg) == false);
	bool finished = false;
	float progress;
	num_pieces = 0;
	boost::recursive_mutex mutex;
	while (!finished)
		boost::tie(finished, progress) = pm->check_files(pieces, num_pieces, mutex);

	TEST_CHECK(num_pieces == std::count(pieces.begin(), pieces.end()
		, true));

	boost::function<void(int, disk_io_job const&)> none;
	TEST_CHECK(exists(test_path / "temp_storage"));
	pm->async_move_storage(test_path / "temp_storage2", none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage"));
	TEST_CHECK(exists(test_path / "temp_storage2/temp_storage"));
	pm->async_move_storage(test_path , none);
	test_sleep(2000);
	TEST_CHECK(!exists(test_path / "temp_storage2/temp_storage"));
	remove_all(test_path / "temp_storage2");

	peer_request r;
	r.piece = 0;
	r.start = 0;
	r.length = piece_size;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece0, piece_size));
	r.piece = 1;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece1, piece_size));
	r.piece = 2;
	pm->async_read(r, bind(&on_read_piece, _1, _2, piece2, piece_size));
	pm->async_release_files(none);

	}
}

void run_test(path const& test_path)
{
	std::cerr << "\n=== " << test_path << " ===\n" << std::endl;

	boost::intrusive_ptr<torrent_info> info(new torrent_info());
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17);
	info->add_file("temp_storage/test2.tmp", 612);
	info->add_file("temp_storage/test3.tmp", 0);
	info->add_file("temp_storage/test4.tmp", 0);
	info->add_file("temp_storage/test5.tmp", 1);

	std::cerr << "=== test 1 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// make sure the files have the correct size
	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17);
	std::cerr << file_size(test_path / "temp_storage" / "test2.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test2.tmp") == 31);
	TEST_CHECK(exists(test_path / "temp_storage/test3.tmp"));
	TEST_CHECK(exists(test_path / "temp_storage/test4.tmp"));
	remove_all(test_path / "temp_storage");

// ==============================================

	// make sure remap_files works
	std::vector<std::pair<std::string, libtorrent::size_type> > map;
	map.push_back(std::make_pair(std::string("temp_storage/test.tmp"), 17 + 612 + 1));
	bool ret = info->remap_files(map);
	TEST_CHECK(ret);

	std::cerr << "=== test 2 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	std::cerr << file_size(test_path / "temp_storage" / "test.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test.tmp") == 48);

	remove_all(test_path / "temp_storage");

// ==============================================

	info = new torrent_info();
	info->set_piece_size(piece_size);
	info->add_file("temp_storage/test1.tmp", 17 + 612 + 1);

	std::cerr << "=== test 3 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_compact);

	// 48 = piece_size * 3
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 48);
	remove_all(test_path / "temp_storage");

// ==============================================

	std::cerr << "=== test 4 ===" << std::endl;

	run_storage_tests(info, test_path, storage_mode_allocate);

	std::cerr << file_size(test_path / "temp_storage" / "test1.tmp") << std::endl;
	TEST_CHECK(file_size(test_path / "temp_storage" / "test1.tmp") == 17 + 612 + 1);

	remove_all(test_path / "temp_storage");
}

int test_main()
{
	std::vector<path> test_paths;
	char* env = std::getenv("TORRENT_TEST_PATHS");
	if (env == 0)
	{
		test_paths.push_back(initial_path());
	}
	else
	{
		char* p = std::strtok(env, ";");
		while (p != 0)
		{
			test_paths.push_back(complete(p));
			p = std::strtok(0, ";");
		}
	}

	std::for_each(test_paths.begin(), test_paths.end(), bind(&run_test, _1));
	return 0;
}

<|endoftext|>


<commit_before>//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Ted Kremenek and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the internal methods used for object serialization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bitcode/Deserialize.h"

#ifdef DEBUG_BACKPATCH
#include "llvm/Support/Streams.h"
#endif

using namespace llvm;

Deserializer::Deserializer(BitstreamReader& stream)
  : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {

  AdvanceStream();
  if (!AtEnd()) StreamStart = BlockStack.back();
}

Deserializer::~Deserializer() {
  assert (RecIdx >= Record.size() &&
          "Still scanning bitcode record when deserialization completed.");

#ifdef DEBUG_BACKPATCH
  for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
    assert (I->first.hasFinalPtr() &&
            "Some pointers were not backpatched.");
#endif
}

bool Deserializer::inRecord() {
  if (Record.size() > 0) {
    if (RecIdx >= Record.size()) {
      RecIdx = 0;
      Record.clear();
      AbbrevNo = 0;
      return false;
    }
    else
      return true;
  }

  return false;
}

bool Deserializer::AdvanceStream() {
  assert (!inRecord() &&
          "Cannot advance stream.  Still processing a record.");

  if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
      AbbrevNo >= bitc::UNABBREV_RECORD)
    return true;

  while (!Stream.AtEndOfStream()) {

    uint64_t Pos = Stream.GetCurrentBitNo();
    AbbrevNo = Stream.ReadCode();

    switch (AbbrevNo) {
      case bitc::ENTER_SUBBLOCK: {
        unsigned id = Stream.ReadSubBlockID();

        // Determine the extent of the block.  This is useful for jumping around
        // the stream.  This is hack: we read the header of the block, save
        // the length, and then revert the bitstream to a location just before
        // the block is entered.
        uint64_t BPos = Stream.GetCurrentBitNo();
        Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
        Stream.SkipToWord();
        unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
        Stream.JumpToBit(BPos);

        BlockStack.push_back(Location(Pos,id,NumWords));
        break;
      }

      case bitc::END_BLOCK: {
        bool x = Stream.ReadBlockEnd();
        assert (!x && "Error at block end.");
        BlockStack.pop_back();
        continue;
      }

      case bitc::DEFINE_ABBREV:
        Stream.ReadAbbrevRecord();
        continue;

      default:
        break;
    }

    return true;
  }

  return false;
}

void Deserializer::ReadRecord() {

  while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
    assert (!BlockStack.empty());
    Stream.EnterSubBlock(BlockStack.back().BlockID);
    AbbrevNo = 0;
  }

  if (Stream.AtEndOfStream())
    return;

  assert (Record.size() == 0);
  assert (AbbrevNo >= bitc::UNABBREV_RECORD);
  RecordCode = Stream.ReadRecord(AbbrevNo,Record);
  assert (Record.size() > 0);
}

void Deserializer::SkipBlock() {
  assert (!inRecord());

  if (AtEnd())
    return;

  AdvanceStream();

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  BlockStack.pop_back();
  Stream.SkipBlock();

  AbbrevNo = 0;
  AdvanceStream();
}

bool Deserializer::SkipToBlock(unsigned BlockID) {
  assert (!inRecord());

  AdvanceStream();
  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

  unsigned BlockLevel = BlockStack.size();

  while (!AtEnd() &&
         BlockLevel == BlockStack.size() &&
         getCurrentBlockID() != BlockID)
    SkipBlock();

  return !(AtEnd() || BlockLevel != BlockStack.size());
}

Deserializer::Location Deserializer::getCurrentBlockLocation() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back();
}

bool Deserializer::JumpTo(const Location& Loc) {

  assert (!inRecord());

//  AdvanceStream();

//  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  uint64_t LastBPos = StreamStart.BitNo;

  while (!BlockStack.empty()) {

    LastBPos = BlockStack.back().BitNo;

    // Determine of the current block contains the location of the block
    // we are looking for.
    if (BlockStack.back().contains(Loc)) {
      // We found the enclosing block.  We must first POP it off to
      // destroy any accumulated context within the block scope.  We then
      // jump to the position of the block and enter it.
      Stream.JumpToBit(LastBPos);
      BlockStack.pop_back();
      Stream.PopBlockScope();

      AbbrevNo = 0;
      AdvanceStream();
      assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

      Stream.EnterSubBlock(BlockStack.back().BlockID);
      break;
    }

    // This block does not contain the block we are looking for.  Pop it.
    BlockStack.pop_back();
    Stream.PopBlockScope();
  }

  // Check if we have popped our way to the outermost scope.  If so,
  // we need to adjust our position.
  if (BlockStack.empty()) {
    Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart.BitNo : LastBPos);
    AbbrevNo = 0;
    AdvanceStream();
  }

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  while (!AtEnd() && BlockStack.back() != Loc) {
    if (BlockStack.back().contains(Loc)) {
      Stream.EnterSubBlock(BlockStack.back().BlockID);
      AbbrevNo = 0;
      AdvanceStream();
      continue;
    }
    else
      SkipBlock();
  }

  if (AtEnd())
    return false;

  assert (BlockStack.back() == Loc);

  return true;
}

unsigned Deserializer::getCurrentBlockID() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back().BlockID;
}

unsigned Deserializer::getRecordCode() {
  if (!inRecord()) {
    AdvanceStream();
    assert (AbbrevNo >= bitc::UNABBREV_RECORD);
    ReadRecord();
  }

  return RecordCode;
}

bool Deserializer::FinishedBlock(Location BlockLoc) {
  if (!inRecord())
    AdvanceStream();

  for (llvm::SmallVector<Location,8>::reverse_iterator
        I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
      if (*I == BlockLoc)
        return false;

  return true;
}

unsigned Deserializer::getAbbrevNo() {
  if (!inRecord())
    AdvanceStream();

  return AbbrevNo;
}

bool Deserializer::AtEnd() {
  if (inRecord())
    return false;

  if (!AdvanceStream())
    return true;

  return false;
}

uint64_t Deserializer::ReadInt() {
  // FIXME: Any error recovery/handling with incomplete or bad files?
  if (!inRecord())
    ReadRecord();

  return Record[RecIdx++];
}

int64_t Deserializer::ReadSInt() {
  uint64_t x = ReadInt();
  int64_t magnitude = x >> 1;
  return x & 0x1 ? -magnitude : magnitude;
}

char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
  if (cstr == NULL)
    MaxLen = 0; // Zero this just in case someone does something funny.

  unsigned len = ReadInt();

  assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);

  if (!cstr)
    cstr = new char[len + (isNullTerm ? 1 : 0)];

  assert (cstr != NULL);

  for (unsigned i = 0; i < len; ++i)
    cstr[i] = (char) ReadInt();

  if (isNullTerm)
    cstr[len+1] = '\0';

  return cstr;
}

void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm) {
  unsigned len = ReadInt();

  buff.clear();
  buff.reserve(len);

  for (unsigned i = 0; i < len; ++i)
    buff.push_back((char) ReadInt());

  if (isNullTerm)
    buff.push_back('\0');
}

void Deserializer::RegisterPtr(unsigned PtrId, const void* Ptr) {
  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (!HasFinalPtr(E) && "Pointer already registered.");

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
#endif

  SetPtr(E,Ptr);
}

void Deserializer::ReadUIntPtr(uintptr_t& PtrRef, bool AllowBackpatch) {
  SerializedPtrID PtrId = ReadPtrID();

  if (PtrId == 0) {
    PtrRef = 0;
    return;
  }

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "ReadUintPtr: " << PtrId << "\n";
#endif

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  if (HasFinalPtr(E))
    PtrRef = GetFinalPtr(E);
  else {
    assert (AllowBackpatch &&
            "Client forbids backpatching for this pointer.");

    // Register backpatch.  Check the freelist for a BPNode.
    BPNode* N;

    if (FreeList) {
      N = FreeList;
      FreeList = FreeList->Next;
    }
    else // No available BPNode.  Allocate one.
      N = (BPNode*) Allocator.Allocate<BPNode>();

    new (N) BPNode(GetBPNode(E),PtrRef);
    SetBPNode(E,N);
  }
}

uintptr_t Deserializer::ReadInternalRefPtr() {
  SerializedPtrID PtrId = ReadPtrID();

  assert (PtrId != 0 && "References cannot refer the NULL address.");

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (HasFinalPtr(E) &&
          "Cannot backpatch references.  Object must be already deserialized.");

  return GetFinalPtr(E);
}

void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
  BPNode* Last = NULL;

  for (BPNode* N = Head; N != NULL; N=N->Next) {
    Last = N;
    N->PtrRef |= reinterpret_cast<uintptr_t>(P);
  }

  if (Last) {
    Last->Next = FreeList;
    FreeList = Head;
  }

  Ptr = const_cast<void*>(P);
}

#define INT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadInt(); }

INT_READ(bool)
INT_READ(unsigned char)
INT_READ(unsigned short)
INT_READ(unsigned int)
INT_READ(unsigned long)

#define SINT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadSInt(); }

INT_READ(signed char)
INT_READ(signed short)
INT_READ(signed int)
INT_READ(signed long)
<commit_msg>Updated method signature to conform with the typedef in the method prototype.<commit_after>//==- Deserialize.cpp - Generic Object Serialization to Bitcode --*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by Ted Kremenek and is distributed under the
// University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the internal methods used for object serialization.
//
//===----------------------------------------------------------------------===//

#include "llvm/Bitcode/Deserialize.h"

#ifdef DEBUG_BACKPATCH
#include "llvm/Support/Streams.h"
#endif

using namespace llvm;

Deserializer::Deserializer(BitstreamReader& stream)
  : Stream(stream), RecIdx(0), FreeList(NULL), AbbrevNo(0), RecordCode(0) {

  AdvanceStream();
  if (!AtEnd()) StreamStart = BlockStack.back();
}

Deserializer::~Deserializer() {
  assert (RecIdx >= Record.size() &&
          "Still scanning bitcode record when deserialization completed.");

#ifdef DEBUG_BACKPATCH
  for (MapTy::iterator I=BPatchMap.begin(), E=BPatchMap.end(); I!=E; ++I)
    assert (I->first.hasFinalPtr() &&
            "Some pointers were not backpatched.");
#endif
}

bool Deserializer::inRecord() {
  if (Record.size() > 0) {
    if (RecIdx >= Record.size()) {
      RecIdx = 0;
      Record.clear();
      AbbrevNo = 0;
      return false;
    }
    else
      return true;
  }

  return false;
}

bool Deserializer::AdvanceStream() {
  assert (!inRecord() &&
          "Cannot advance stream.  Still processing a record.");

  if (AbbrevNo == bitc::ENTER_SUBBLOCK ||
      AbbrevNo >= bitc::UNABBREV_RECORD)
    return true;

  while (!Stream.AtEndOfStream()) {

    uint64_t Pos = Stream.GetCurrentBitNo();
    AbbrevNo = Stream.ReadCode();

    switch (AbbrevNo) {
      case bitc::ENTER_SUBBLOCK: {
        unsigned id = Stream.ReadSubBlockID();

        // Determine the extent of the block.  This is useful for jumping around
        // the stream.  This is hack: we read the header of the block, save
        // the length, and then revert the bitstream to a location just before
        // the block is entered.
        uint64_t BPos = Stream.GetCurrentBitNo();
        Stream.ReadVBR(bitc::CodeLenWidth); // Skip the code size.
        Stream.SkipToWord();
        unsigned NumWords = Stream.Read(bitc::BlockSizeWidth);
        Stream.JumpToBit(BPos);

        BlockStack.push_back(Location(Pos,id,NumWords));
        break;
      }

      case bitc::END_BLOCK: {
        bool x = Stream.ReadBlockEnd();
        assert (!x && "Error at block end.");
        BlockStack.pop_back();
        continue;
      }

      case bitc::DEFINE_ABBREV:
        Stream.ReadAbbrevRecord();
        continue;

      default:
        break;
    }

    return true;
  }

  return false;
}

void Deserializer::ReadRecord() {

  while (AdvanceStream() && AbbrevNo == bitc::ENTER_SUBBLOCK) {
    assert (!BlockStack.empty());
    Stream.EnterSubBlock(BlockStack.back().BlockID);
    AbbrevNo = 0;
  }

  if (Stream.AtEndOfStream())
    return;

  assert (Record.size() == 0);
  assert (AbbrevNo >= bitc::UNABBREV_RECORD);
  RecordCode = Stream.ReadRecord(AbbrevNo,Record);
  assert (Record.size() > 0);
}

void Deserializer::SkipBlock() {
  assert (!inRecord());

  if (AtEnd())
    return;

  AdvanceStream();

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  BlockStack.pop_back();
  Stream.SkipBlock();

  AbbrevNo = 0;
  AdvanceStream();
}

bool Deserializer::SkipToBlock(unsigned BlockID) {
  assert (!inRecord());

  AdvanceStream();
  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

  unsigned BlockLevel = BlockStack.size();

  while (!AtEnd() &&
         BlockLevel == BlockStack.size() &&
         getCurrentBlockID() != BlockID)
    SkipBlock();

  return !(AtEnd() || BlockLevel != BlockStack.size());
}

Deserializer::Location Deserializer::getCurrentBlockLocation() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back();
}

bool Deserializer::JumpTo(const Location& Loc) {

  assert (!inRecord());

//  AdvanceStream();

//  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  uint64_t LastBPos = StreamStart.BitNo;

  while (!BlockStack.empty()) {

    LastBPos = BlockStack.back().BitNo;

    // Determine of the current block contains the location of the block
    // we are looking for.
    if (BlockStack.back().contains(Loc)) {
      // We found the enclosing block.  We must first POP it off to
      // destroy any accumulated context within the block scope.  We then
      // jump to the position of the block and enter it.
      Stream.JumpToBit(LastBPos);
      BlockStack.pop_back();
      Stream.PopBlockScope();

      AbbrevNo = 0;
      AdvanceStream();
      assert (AbbrevNo == bitc::ENTER_SUBBLOCK);

      Stream.EnterSubBlock(BlockStack.back().BlockID);
      break;
    }

    // This block does not contain the block we are looking for.  Pop it.
    BlockStack.pop_back();
    Stream.PopBlockScope();
  }

  // Check if we have popped our way to the outermost scope.  If so,
  // we need to adjust our position.
  if (BlockStack.empty()) {
    Stream.JumpToBit(Loc.BitNo < LastBPos ? StreamStart.BitNo : LastBPos);
    AbbrevNo = 0;
    AdvanceStream();
  }

  assert (AbbrevNo == bitc::ENTER_SUBBLOCK);
  assert (!BlockStack.empty());

  while (!AtEnd() && BlockStack.back() != Loc) {
    if (BlockStack.back().contains(Loc)) {
      Stream.EnterSubBlock(BlockStack.back().BlockID);
      AbbrevNo = 0;
      AdvanceStream();
      continue;
    }
    else
      SkipBlock();
  }

  if (AtEnd())
    return false;

  assert (BlockStack.back() == Loc);

  return true;
}

unsigned Deserializer::getCurrentBlockID() {
  if (!inRecord())
    AdvanceStream();

  return BlockStack.back().BlockID;
}

unsigned Deserializer::getRecordCode() {
  if (!inRecord()) {
    AdvanceStream();
    assert (AbbrevNo >= bitc::UNABBREV_RECORD);
    ReadRecord();
  }

  return RecordCode;
}

bool Deserializer::FinishedBlock(Location BlockLoc) {
  if (!inRecord())
    AdvanceStream();

  for (llvm::SmallVector<Location,8>::reverse_iterator
        I=BlockStack.rbegin(), E=BlockStack.rend(); I!=E; ++I)
      if (*I == BlockLoc)
        return false;

  return true;
}

unsigned Deserializer::getAbbrevNo() {
  if (!inRecord())
    AdvanceStream();

  return AbbrevNo;
}

bool Deserializer::AtEnd() {
  if (inRecord())
    return false;

  if (!AdvanceStream())
    return true;

  return false;
}

uint64_t Deserializer::ReadInt() {
  // FIXME: Any error recovery/handling with incomplete or bad files?
  if (!inRecord())
    ReadRecord();

  return Record[RecIdx++];
}

int64_t Deserializer::ReadSInt() {
  uint64_t x = ReadInt();
  int64_t magnitude = x >> 1;
  return x & 0x1 ? -magnitude : magnitude;
}

char* Deserializer::ReadCStr(char* cstr, unsigned MaxLen, bool isNullTerm) {
  if (cstr == NULL)
    MaxLen = 0; // Zero this just in case someone does something funny.

  unsigned len = ReadInt();

  assert (MaxLen == 0 || (len + (isNullTerm ? 1 : 0)) <= MaxLen);

  if (!cstr)
    cstr = new char[len + (isNullTerm ? 1 : 0)];

  assert (cstr != NULL);

  for (unsigned i = 0; i < len; ++i)
    cstr[i] = (char) ReadInt();

  if (isNullTerm)
    cstr[len+1] = '\0';

  return cstr;
}

void Deserializer::ReadCStr(std::vector<char>& buff, bool isNullTerm) {
  unsigned len = ReadInt();

  buff.clear();
  buff.reserve(len);

  for (unsigned i = 0; i < len; ++i)
    buff.push_back((char) ReadInt());

  if (isNullTerm)
    buff.push_back('\0');
}

void Deserializer::RegisterPtr(SerializedPtrID PtrId, const void* Ptr) {
  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (!HasFinalPtr(E) && "Pointer already registered.");

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "RegisterPtr: " << PtrId << " => " << Ptr << "\n";
#endif

  SetPtr(E,Ptr);
}

void Deserializer::ReadUIntPtr(uintptr_t& PtrRef, bool AllowBackpatch) {
  SerializedPtrID PtrId = ReadPtrID();

  if (PtrId == 0) {
    PtrRef = 0;
    return;
  }

#ifdef DEBUG_BACKPATCH
  llvm::cerr << "ReadUintPtr: " << PtrId << "\n";
#endif

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  if (HasFinalPtr(E))
    PtrRef = GetFinalPtr(E);
  else {
    assert (AllowBackpatch &&
            "Client forbids backpatching for this pointer.");

    // Register backpatch.  Check the freelist for a BPNode.
    BPNode* N;

    if (FreeList) {
      N = FreeList;
      FreeList = FreeList->Next;
    }
    else // No available BPNode.  Allocate one.
      N = (BPNode*) Allocator.Allocate<BPNode>();

    new (N) BPNode(GetBPNode(E),PtrRef);
    SetBPNode(E,N);
  }
}

uintptr_t Deserializer::ReadInternalRefPtr() {
  SerializedPtrID PtrId = ReadPtrID();

  assert (PtrId != 0 && "References cannot refer the NULL address.");

  MapTy::value_type& E = BPatchMap.FindAndConstruct(BPKey(PtrId));

  assert (HasFinalPtr(E) &&
          "Cannot backpatch references.  Object must be already deserialized.");

  return GetFinalPtr(E);
}

void Deserializer::BPEntry::SetPtr(BPNode*& FreeList, void* P) {
  BPNode* Last = NULL;

  for (BPNode* N = Head; N != NULL; N=N->Next) {
    Last = N;
    N->PtrRef |= reinterpret_cast<uintptr_t>(P);
  }

  if (Last) {
    Last->Next = FreeList;
    FreeList = Head;
  }

  Ptr = const_cast<void*>(P);
}

#define INT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadInt(); }

INT_READ(bool)
INT_READ(unsigned char)
INT_READ(unsigned short)
INT_READ(unsigned int)
INT_READ(unsigned long)

#define SINT_READ(TYPE)\
void SerializeTrait<TYPE>::Read(Deserializer& D, TYPE& X) {\
  X = (TYPE) D.ReadSInt(); }

INT_READ(signed char)
INT_READ(signed short)
INT_READ(signed int)
INT_READ(signed long)
<|endoftext|>


<commit_before>#include <string>
#include <utility>

#include <gtest/gtest.h>

#include <sauce/sauce.h>

namespace sauce_tutorial { // Put in a different namespace, forcing us to show off "using" statements.
namespace test {

/**
 * This suite is intended to be a complete (if stubbed) example of how sauce might be used to manage the dependencies
 * of a typical MVC-like application.  Unlike binding_test, whose aim is coverage across all variations of binding and
 * use, the focus here is on clarity and documentation.
 *
 * Suppose we are creating a web application allowing a Mom & Pop pizza parlour to accept orders online.  Customers can
 * choose toppings, sauce (ha!) and crust, specify take-out or delivery (giving an address as needed) and later inspect
 * the progress of their order.  An employee at the store uses a similar interface to declare when an order has
 * started, left for delivery, etc.  This application runs in a three-tier architecture of a web server backed by app
 * processes talking to a single relational database.
 *
 * Even in this simple application there is complexity to manage, which can be addressed by following the MVC pattern.
 * Vanilla MVC articulates a useful separation of concerns and wraps each in an object.  However it is silent about how
 * those objects are ultimately assembled into the final application; this is where dependency injection (and sauce)
 * can help.
 *
 * Since the point of the technique is to keep components decoupled and unaware of each other, a real application would
 * likely spread its components out across many headers and compilation units.  This poses no problem for sauce, but
 * for clarity everything in this example is contained in this suite.  Comments indicate where suggested file breaks
 * might occur.
 */

// ********************************************************************************************************************
// orm.h

/**
 * This is not part of the pizza application proper, but is a library used by the application author to manage access
 * to the database.  It does so by materializing rows as application objects in memory, hiding details (like SQL) from
 * the application author.
 */

// ********************************************************************************************************************
// web.h

using sauce::Injector;
using sauce::AbstractProvider;
using sauce::Provider;

/**
 * This is a library to supplying url routing, controller-related interfaces and Application to tie it together.
 *
 * This example uses sauce also as a type registry for controllers, as a way of showing off implicit injector injection
 * and the dynamic name feature.
 */

// Have some interfaces.
struct Request {};
struct Response {};

struct Controller {
  virtual void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) = 0;
};

typedef std::string RequestPattern;

struct Router {
  sauce::shared_ptr<Injector> injector;

  /**
   * Notice that a Router depends on having an injector itself, which sauce satisfies even though no injector is
   * explicitly bound.
   */
  Router(sauce::shared_ptr<Injector> injector):
    injector(injector) {}

  void map(RequestPattern, std::string /* controllerName */) {} // One could imagine this building up a pattern index.
  virtual void wire() = 0;                                      // Override to supposedly declare routes.

  /**
   * Accept a Request and produce a Controller suitable to serve it.
   */
  sauce::shared_ptr<Controller> route(sauce::shared_ptr<Request>) {
    // Without writing an actual router, let's just pretend the first matching RequestPattern is mapped to "place".
    std::string selectedController = "place"; // = firstMatch(request);

    /**
     * We now have the task of taking a (essentially arbitrary) string and producing the controller it names.  Sauce
     * would be the ideal way to assemble the chosen Controller, but it's not clear how to tell sauce which one we
     * want.
     *
     * The dynamic naming feature helps us here.  First, observe (below) that all controllers are bound, under the same
     * interface type (Controller) but with different string names.  Being fixed only at binding time, these names are
     * called "dynamic" names (as opposed to "static" names, which are type tags.)  Dynamic names let us make a
     * selection from known possibilities at runtime.  Specifically, they can enable a configuration-driven plugin
     * framework, which is the one thing static dependency names can't do.
     *
     * Here, we use it to select the desired controller; the name (which is always a std::string) is passed to get().
     */
    return injector->get<Controller>(selectedController);
  }
};

typedef std::pair<sauce::shared_ptr<Request>, sauce::shared_ptr<Response> > RequestResponsePair;

/**
 * Receives new request, response pairs from the web server.
 */
struct Acceptor {
  /**
   * Block until a request to process arrives.
   */
  virtual RequestResponsePair accept() = 0;
};

/**
 * An Acceptor supposedly driven by a local FCGI environment.
 *
 * FCGIAcceptor requires two injected dependencies, a provider for requests and one for responses.  A provider is a
 * factory that allows one to request instances of the provided type (request or response) on demand.  It allows the
 * application developer to declare a dependency on a type without committed to how many instances of that type are
 * needed.
 *
 * Since our acceptor is responsible for producing requests (with paired responses) waiting to be served, it needs an
 * unlimited number of them.  However it doesn't want to be resposible for all the assembly details of making a
 * request, it just wants an opportunity to modify it before it gets handed to the router.  An injected provider fits
 * this need well.
 */
struct FCGIAcceptor: public Acceptor {
  sauce::shared_ptr<Provider<Request> > requestProvider;
  sauce::shared_ptr<Provider<Response> > responseProvider;

  FCGIAcceptor(sauce::shared_ptr<Provider<Request> > requestProvider,
               sauce::shared_ptr<Provider<Response> > responseProvider):
    requestProvider(requestProvider),
    responseProvider(responseProvider) {}

  RequestResponsePair accept() {
    sauce::shared_ptr<Request> request = requestProvider->get();
    sauce::shared_ptr<Response> response = responseProvider->get();
    // fcgiAccept(&request.socket, &response.socket);
    return std::make_pair(request, response);
  }
};

/**
 * An application encapsulates the request cycle of single-threaded app worker.
 */
struct Application {
  sauce::shared_ptr<Acceptor> acceptor;
  sauce::shared_ptr<Router> router;

  Application(sauce::shared_ptr<Acceptor> acceptor,
              sauce::shared_ptr<Router> router):
    acceptor(acceptor),
    router(router) {}

  void run() {
    while (true) {
      serveOne();
    }
  }

  void serveOne() {
    RequestResponsePair requestResponse = acceptor->accept();
    sauce::shared_ptr<Request> request = requestResponse.first;
    sauce::shared_ptr<Response> response = requestResponse.second;

    sauce::shared_ptr<Controller> controller = router->route(request);
    controller->serve(request, response);
  }
};

// ********************************************************************************************************************
// routes.h

/**
 * Here are the application author-supplied mappings between url patterns and controllers in our ficticuous framework.
 */

struct MyRouter: public Router {
  // TODO: Setter injection would allow us to expose an inherited setter, instead of delegating in the constructor.
  MyRouter(sauce::shared_ptr<Injector> injector):
    Router(injector) {}

  void wire() {
    map("/orders/new(/.*)?", "place");
    map("/status", "status");
  }
};

// ********************************************************************************************************************
// models.h

/**
 * A pizza order being processed.
 */

// ********************************************************************************************************************
// controllers.h

/**
 * Handles requests to place an order.
 */
struct PlaceController: public Controller {
  void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) {}
};

/**
 * Handles requests regarding an order's status.
 */
struct StatusController: public Controller {
  void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) {}
};

// ********************************************************************************************************************
// place_controller_test.cc

/**
 * The unit test suite for PlaceController, demonstrating how to inject mocks or stubs.
 */

using sauce::Binder;

struct StubRequest: public Request {};
struct StubResponse: public Response {};

/**
 * The sauce module, written by the application author, that specifies bindings for this unit test suite.
 *
 * Modules are collections of bindings, which tell sauce how interface requests should be satisfied.  The application
 * author tells sauce about bindings with a "fluent" API exposed either by the passed Binder or inherited from
 * AbstractModule (see below.)
 *
 * Each binding begins with a call to bind, passing the interface to be bound as a template parameter.  Further chained
 * calls declare what concrete implementation should be used, and customize how to make or find it.
 */
void MockModule(Binder & binder) {
  /**
   * The result of bind() (an intermediate with an annoyingly complex type) is invoked in turn.
   *
   * Here, to<StubRequest()>() says that requests for the interface Request should be satisfied with instances of the
   * StubRequest concrete type.
   *
   * StubRequest() is actually a function type.  This is how we specify which constructor to use.  If the chosen
   * constructor takes arguments, they are treated as dependencies and satisfied first.
   */
  binder.bind<Request>().to<StubRequest()>();

  // Here's another
  binder.bind<Response>().to<StubResponse()>();
}

// ********************************************************************************************************************
// production_module.cc

using sauce::AbstractModule;
using sauce::Provider;

/**
 * The sauce module, written by the application author, that specifies the bindings used when running in production.
 *
 * Concretely, a module is either a void (Binder &) function as above, or a class deriving from AbstractModule as is
 * the case here. (Technically any type providing a void operator()(Binder & binder) will do.)
 *
 * The difference is just sugar: the AbstractModule doesn't need to prefix bindings with "binder." while the function
 * is conceptually simpler and more concrete.
 */
class ProductionModule: public AbstractModule {
  void configure() {
    /**
     * Here there is no Binder, we just call bind<Iface>() directly.
     */

    /**
     * MyRouter depends on having access to the injector itself but no injector is bound, nor is it obvious how to
     * declare such a binding.  Sauce addresses this with an "implicit" binding: requests for the injector are
     * ultimately satisfied with the same injector that the initial e.g. get() call was made to.
     *
     * As an aside, it's generally considered bad practice to rely on this feature heavily, since it obscures what the
     * real dependencies are.  Here, the Router only wants access to Controllers bound with various dynamic names, but
     * inspecting the module alone can't tell us that: all we can see is it could request anything.  Still, the feature
     * has its uses.
     */
    bind<Router>().to<MyRouter(Injector)>();

    /**
     * Bindings can be named.  The same interface can be bound multiple times, so long as the bindings have different
     * names.  When requesting an injection, either by Injector::get or as a dependency of another binding, a name can
     * be specified to select amongst the alternative bindings.
     *
     * Names come in two flavors.  Dynamic names are opaque standard strings, where static names are type decorators:
     * instead of "bind<Controller>()" one says "bind<Named<Controller, ArbitraryTypeTag> >()".
     *
     * Bind the two controllers under dynamic names (see Router above for an example of selecting between them.)
     */
    bind<Controller>().named("place").to<PlaceController()>();

    // TODO: would be nice if "to<StatusController>()" was equivalent to "to<StatusController()>()"..
    bind<Controller>().named("status").to<StatusController()>();
  }
};

/**
 * The sauce module, written by the framework author, that specifies the bindings used when running in production.
 *
 * Modules can work cooperatively, and can be sourced from different compilation units (or dlsym'd libraries, etc.)
 */
class FrameworkModule: public AbstractModule {
  void configure() {
    /**
     * It's not required to have a separate interface; here we bind types to their own constructor.
     */
    bind<Request>().to<Request()>();
    bind<Response>().to<Response()>();

    /**
     * Notice that the injected types are references.  This side-steps a problem with how sauce abuses the type system.
     * Specifically, since Acceptor and Router each contain pure-virtual methods, they can't be passed by value.  This
     * implies it's illegal to even formulate a function type that would do so.
     *
     * Note sauce never really was going to pass by value: it uses smart pointers for everything.  The value parameter
     * syntax just happens to be less cluttered.  When this results in an illegal function type, a reference may be
     * used instead; sauce will just strip it off (and smart pointers to references don't make sense anyway.)
     */
    bind<Application>().to<Application(Acceptor &, Router &)>();

    /**
     * Notice we never bound a Provider<Request>, but only a Request.  This is an example of an implicit binding that
     * sauce supplies.  Since it knows how to make requests, it can synthesize a provider that makes them in the same
     * way.
     */
    bind<Acceptor>().to<FCGIAcceptor(Provider<Request> &, Provider<Response> &)>();
  }
};

// ********************************************************************************************************************
// main.cc

using sauce::Modules;
using sauce::Injector;

/**
 * The entry point of the application, and where sauce injects dependencies.
 */
TEST(TutorialTest, main) { // Let's pretend this is main()
  /**
   * Create an injector by first choosing what modules to use.  These are accumulated in a Modules object.
   * More than one module can be selected, allowing the application developer to mix and match.
   */
  Modules modules;
  modules.add(ProductionModule());
  modules.add(FrameworkModule());

  /**
   * After desired modules are added, use createInjector() to get an injector itself.
   *
   * It is returned as a sauce::shared_ptr, which is just an alias for std::shared_ptr (though std::tr1 and boost smart
   * pointers can be used, if the SAUCE_STD_TR1_SMART_PTR or SAUCE_BOOST_SMART_PTR preprocessor symbols are defined.)
   */
  sauce::shared_ptr<Injector> injector = modules.createInjector();

  /**
   * We're now free to ask the injector to supply various interfaces.  Let's create an Application and serve a request.
   */
  sauce::shared_ptr<Application> application = injector->get<Application>();
  application->serveOne();

  ASSERT_TRUE(true);
}

}
}
<commit_msg>Simplify our story a touch.<commit_after>#include <string>
#include <utility>

#include <gtest/gtest.h>

#include <sauce/sauce.h>

namespace sauce_tutorial { // Put in a different namespace, forcing us to show off "using" statements.
namespace test {

/**
 * This suite is intended to be a complete (if stubbed) example of how sauce might be used to manage the dependencies
 * of a typical MVC-like application.  Unlike binding_test, whose aim is coverage across all variations of binding and
 * use, the focus here is on clarity and documentation.
 *
 * Suppose we are creating a web application allowing a Mom & Pop pizza parlour to accept orders online.  Customers can
 * place orders and later inspect order status.  This application runs in a three-tier architecture of a web server
 * backed by app processes talking to a single relational database.
 *
 * Even in this simple application there is complexity to manage, which can be addressed by following the MVC pattern.
 * Vanilla MVC articulates a useful separation of concerns and wraps each in an object.  However it is silent about how
 * those objects are ultimately assembled into the final application; this is where dependency injection (and sauce)
 * can help.
 *
 * Since the point of the technique is to keep components decoupled and unaware of each other, a real application would
 * likely spread its components out across many headers and compilation units.  This poses no problem for sauce, but
 * for clarity everything in this example is contained in this suite.  Comments indicate where suggested file breaks
 * might occur.
 */

// ********************************************************************************************************************
// orm.h

/**
 * This is not part of the pizza application proper, but is a library used by the application author to manage access
 * to the database.  It does so by materializing rows as application objects in memory, hiding details (like SQL) from
 * the application author.
 */

// ********************************************************************************************************************
// web.h

using sauce::Injector;
using sauce::AbstractProvider;
using sauce::Provider;

/**
 * This is a library to supplying url routing, controller-related interfaces and Application to tie it together.
 *
 * This example uses sauce also as a type registry for controllers, as a way of showing off implicit injector injection
 * and the dynamic name feature.
 */

// Have some interfaces.
struct Request {};
struct Response {};

struct Controller {
  virtual void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) = 0;
};

typedef std::string RequestPattern;

struct Router {
  sauce::shared_ptr<Injector> injector;

  /**
   * Notice that a Router depends on having an injector itself, which sauce satisfies even though no injector is
   * explicitly bound.
   */
  Router(sauce::shared_ptr<Injector> injector):
    injector(injector) {}

  void map(RequestPattern, std::string /* controllerName */) {} // One could imagine this building up a pattern index.
  virtual void wire() = 0;                                      // Override to supposedly declare routes.

  /**
   * Accept a Request and produce a Controller suitable to serve it.
   */
  sauce::shared_ptr<Controller> route(sauce::shared_ptr<Request>) {
    // Without writing an actual router, let's just pretend the first matching RequestPattern is mapped to "place".
    std::string selectedController = "place"; // = firstMatch(request);

    /**
     * We now have the task of taking a (essentially arbitrary) string and producing the controller it names.  Sauce
     * would be the ideal way to assemble the chosen Controller, but it's not clear how to tell sauce which one we
     * want.
     *
     * The dynamic naming feature helps us here.  First, observe (below) that all controllers are bound, under the same
     * interface type (Controller) but with different string names.  Being fixed only at binding time, these names are
     * called "dynamic" names (as opposed to "static" names, which are type tags.)  Dynamic names let us make a
     * selection from known possibilities at runtime.  Specifically, they can enable a configuration-driven plugin
     * framework, which is the one thing static dependency names can't do.
     *
     * Here, we use it to select the desired controller; the name (which is always a std::string) is passed to get().
     */
    return injector->get<Controller>(selectedController);
  }
};

typedef std::pair<sauce::shared_ptr<Request>, sauce::shared_ptr<Response> > RequestResponsePair;

/**
 * Receives new request, response pairs from the web server.
 */
struct Acceptor {
  /**
   * Block until a request to process arrives.
   */
  virtual RequestResponsePair accept() = 0;
};

/**
 * An Acceptor supposedly driven by a local FCGI environment.
 *
 * FCGIAcceptor requires two injected dependencies, a provider for requests and one for responses.  A provider is a
 * factory that allows one to request instances of the provided type (request or response) on demand.  It allows the
 * application developer to declare a dependency on a type without committed to how many instances of that type are
 * needed.
 *
 * Since our acceptor is responsible for producing requests (with paired responses) waiting to be served, it needs an
 * unlimited number of them.  However it doesn't want to be resposible for all the assembly details of making a
 * request, it just wants an opportunity to modify it before it gets handed to the router.  An injected provider fits
 * this need well.
 */
struct FCGIAcceptor: public Acceptor {
  sauce::shared_ptr<Provider<Request> > requestProvider;
  sauce::shared_ptr<Provider<Response> > responseProvider;

  FCGIAcceptor(sauce::shared_ptr<Provider<Request> > requestProvider,
               sauce::shared_ptr<Provider<Response> > responseProvider):
    requestProvider(requestProvider),
    responseProvider(responseProvider) {}

  RequestResponsePair accept() {
    sauce::shared_ptr<Request> request = requestProvider->get();
    sauce::shared_ptr<Response> response = responseProvider->get();
    // fcgiAccept(&request.socket, &response.socket);
    return std::make_pair(request, response);
  }
};

/**
 * An application encapsulates the request cycle of single-threaded app worker.
 */
struct Application {
  sauce::shared_ptr<Acceptor> acceptor;
  sauce::shared_ptr<Router> router;

  Application(sauce::shared_ptr<Acceptor> acceptor,
              sauce::shared_ptr<Router> router):
    acceptor(acceptor),
    router(router) {}

  void run() {
    while (true) {
      serveOne();
    }
  }

  void serveOne() {
    RequestResponsePair requestResponse = acceptor->accept();
    sauce::shared_ptr<Request> request = requestResponse.first;
    sauce::shared_ptr<Response> response = requestResponse.second;

    sauce::shared_ptr<Controller> controller = router->route(request);
    controller->serve(request, response);
  }
};

// ********************************************************************************************************************
// routes.h

/**
 * Here are the application author-supplied mappings between url patterns and controllers in our ficticuous framework.
 */

struct MyRouter: public Router {
  // TODO: Setter injection would allow us to expose an inherited setter, instead of delegating in the constructor.
  MyRouter(sauce::shared_ptr<Injector> injector):
    Router(injector) {}

  void wire() {
    map("/orders/new(/.*)?", "place");
    map("/status", "status");
  }
};

// ********************************************************************************************************************
// models.h

/**
 * A pizza order being processed.
 */

// ********************************************************************************************************************
// controllers.h

/**
 * Handles requests to place an order.
 */
struct PlaceController: public Controller {
  void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) {}
};

/**
 * Handles requests regarding an order's status.
 */
struct StatusController: public Controller {
  void serve(sauce::shared_ptr<Request>, sauce::shared_ptr<Response>) {}
};

// ********************************************************************************************************************
// place_controller_test.cc

/**
 * The unit test suite for PlaceController, demonstrating how to inject mocks or stubs.
 */

using sauce::Binder;

struct StubRequest: public Request {};
struct StubResponse: public Response {};

/**
 * The sauce module, written by the application author, that specifies bindings for this unit test suite.
 *
 * Modules are collections of bindings, which tell sauce how interface requests should be satisfied.  The application
 * author tells sauce about bindings with a "fluent" API exposed either by the passed Binder or inherited from
 * AbstractModule (see below.)
 *
 * Each binding begins with a call to bind, passing the interface to be bound as a template parameter.  Further chained
 * calls declare what concrete implementation should be used, and customize how to make or find it.
 */
void MockModule(Binder & binder) {
  /**
   * The result of bind() (an intermediate with an annoyingly complex type) is invoked in turn.
   *
   * Here, to<StubRequest()>() says that requests for the interface Request should be satisfied with instances of the
   * StubRequest concrete type.
   *
   * StubRequest() is actually a function type.  This is how we specify which constructor to use.  If the chosen
   * constructor takes arguments, they are treated as dependencies and satisfied first.
   */
  binder.bind<Request>().to<StubRequest()>();

  // Here's another
  binder.bind<Response>().to<StubResponse()>();
}

// ********************************************************************************************************************
// production_module.cc

using sauce::AbstractModule;
using sauce::Provider;

/**
 * The sauce module, written by the application author, that specifies the bindings used when running in production.
 *
 * Concretely, a module is either a void (Binder &) function as above, or a class deriving from AbstractModule as is
 * the case here. (Technically any type providing a void operator()(Binder & binder) will do.)
 *
 * The difference is just sugar: the AbstractModule doesn't need to prefix bindings with "binder." while the function
 * is conceptually simpler and more concrete.
 */
class ProductionModule: public AbstractModule {
  void configure() {
    /**
     * Here there is no Binder, we just call bind<Iface>() directly.
     */

    /**
     * MyRouter depends on having access to the injector itself but no injector is bound, nor is it obvious how to
     * declare such a binding.  Sauce addresses this with an "implicit" binding: requests for the injector are
     * ultimately satisfied with the same injector that the initial e.g. get() call was made to.
     *
     * As an aside, it's generally considered bad practice to rely on this feature heavily, since it obscures what the
     * real dependencies are.  Here, the Router only wants access to Controllers bound with various dynamic names, but
     * inspecting the module alone can't tell us that: all we can see is it could request anything.  Still, the feature
     * has its uses.
     */
    bind<Router>().to<MyRouter(Injector)>();

    /**
     * Bindings can be named.  The same interface can be bound multiple times, so long as the bindings have different
     * names.  When requesting an injection, either by Injector::get or as a dependency of another binding, a name can
     * be specified to select amongst the alternative bindings.
     *
     * Names come in two flavors.  Dynamic names are opaque standard strings, where static names are type decorators:
     * instead of "bind<Controller>()" one says "bind<Named<Controller, ArbitraryTypeTag> >()".
     *
     * Bind the two controllers under dynamic names (see Router above for an example of selecting between them.)
     */
    bind<Controller>().named("place").to<PlaceController()>();

    // TODO: would be nice if "to<StatusController>()" was equivalent to "to<StatusController()>()"..
    bind<Controller>().named("status").to<StatusController()>();
  }
};

/**
 * The sauce module, written by the framework author, that specifies the bindings used when running in production.
 *
 * Modules can work cooperatively, and can be sourced from different compilation units (or dlsym'd libraries, etc.)
 */
class FrameworkModule: public AbstractModule {
  void configure() {
    /**
     * It's not required to have a separate interface; here we bind types to their own constructor.
     */
    bind<Request>().to<Request()>();
    bind<Response>().to<Response()>();

    /**
     * Notice that the injected types are references.  This side-steps a problem with how sauce abuses the type system.
     * Specifically, since Acceptor and Router each contain pure-virtual methods, they can't be passed by value.  This
     * implies it's illegal to even formulate a function type that would do so.
     *
     * Note sauce never really was going to pass by value: it uses smart pointers for everything.  The value parameter
     * syntax just happens to be less cluttered.  When this results in an illegal function type, a reference may be
     * used instead; sauce will just strip it off (and smart pointers to references don't make sense anyway.)
     */
    bind<Application>().to<Application(Acceptor &, Router &)>();

    /**
     * Notice we never bound a Provider<Request>, but only a Request.  This is an example of an implicit binding that
     * sauce supplies.  Since it knows how to make requests, it can synthesize a provider that makes them in the same
     * way.
     */
    bind<Acceptor>().to<FCGIAcceptor(Provider<Request> &, Provider<Response> &)>();
  }
};

// ********************************************************************************************************************
// main.cc

using sauce::Modules;
using sauce::Injector;

/**
 * The entry point of the application, and where sauce injects dependencies.
 */
TEST(TutorialTest, main) { // Let's pretend this is main()
  /**
   * Create an injector by first choosing what modules to use.  These are accumulated in a Modules object.
   * More than one module can be selected, allowing the application developer to mix and match.
   */
  Modules modules;
  modules.add(ProductionModule());
  modules.add(FrameworkModule());

  /**
   * After desired modules are added, use createInjector() to get an injector itself.
   *
   * It is returned as a sauce::shared_ptr, which is just an alias for std::shared_ptr (though std::tr1 and boost smart
   * pointers can be used, if the SAUCE_STD_TR1_SMART_PTR or SAUCE_BOOST_SMART_PTR preprocessor symbols are defined.)
   */
  sauce::shared_ptr<Injector> injector = modules.createInjector();

  /**
   * We're now free to ask the injector to supply various interfaces.  Let's create an Application and serve a request.
   */
  sauce::shared_ptr<Application> application = injector->get<Application>();
  application->serveOne();

  ASSERT_TRUE(true);
}

}
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_config.h"
#include "string_list.h"

#include "nordugridresource.h"
#include "nordugridjob.h"
#include "gridmanager.h"

#define HASH_TABLE_SIZE			500

HashTable <HashKey, NordugridResource *>
    NordugridResource::ResourcesByName( HASH_TABLE_SIZE,
										hashFunction );

const char *NordugridResource::HashName( const char *resource_name,
										 const char *proxy_subject )
{
	static std::string hash_name;

	formatstr( hash_name, "nordugrid %s#%s", resource_name,
					   proxy_subject ? proxy_subject : "NULL" );

	return hash_name.c_str();
}

NordugridResource *NordugridResource::FindOrCreateResource( const char * resource_name,
															const Proxy *proxy )
{
	int rc;
	NordugridResource *resource = NULL;

	rc = ResourcesByName.lookup( HashKey( HashName( resource_name,
													proxy->subject->fqan ) ),
								 resource );
	if ( rc != 0 ) {
		resource = new NordugridResource( resource_name, proxy );
		ASSERT(resource);
		resource->Reconfig();
		ResourcesByName.insert( HashKey( HashName( resource_name,
												   proxy->subject->fqan ) ),
								resource );
	} else {
		ASSERT(resource);
	}

	return resource;
}

NordugridResource::NordugridResource( const char *resource_name,
									  const Proxy *proxy )
	: BaseResource( resource_name )
{
	proxySubject = strdup( proxy->subject->subject_name );
	proxyFQAN = strdup( proxy->subject->fqan );

	gahp = NULL;

	std::string buff;
	formatstr( buff, "NORDUGRID/%s", proxyFQAN );

	gahp = new GahpClient( buff.c_str() );
	gahp->setNotificationTimerId( pingTimerId );
	gahp->setMode( GahpClient::normal );
	gahp->setTimeout( NordugridJob::gahpCallTimeout );

	m_jobStatusTid = daemonCore->Register_Timer( 0,
							(TimerHandlercpp)&NordugridResource::DoJobStatus,
							"NordugridResource::DoJobStatus", (Service*)this );

	m_statusGahp = new GahpClient( buff.c_str() );
	m_statusGahp->setNotificationTimerId( m_jobStatusTid );
	m_statusGahp->setMode( GahpClient::normal );
	m_statusGahp->setTimeout( NordugridJob::gahpCallTimeout );

	m_jobStatusActive = false;
}

NordugridResource::~NordugridResource()
{
	ResourcesByName.remove( HashKey( HashName( resourceName, proxyFQAN ) ) );
	free( proxyFQAN );
	if ( proxySubject ) {
		free( proxySubject );
	}
	if ( gahp ) {
		delete gahp;
	}
	delete m_statusGahp;
	if ( m_jobStatusTid != TIMER_UNSET ) {
		daemonCore->Cancel_Timer( m_jobStatusTid );
	}
}

void NordugridResource::Reconfig()
{
	BaseResource::Reconfig();

	gahp->setTimeout( NordugridJob::gahpCallTimeout );
}

const char *NordugridResource::ResourceType()
{
	return "nordugrid";
}

const char *NordugridResource::GetHashName()
{
	return HashName( resourceName, proxyFQAN );
}

void NordugridResource::PublishResourceAd( ClassAd *resource_ad )
{
	BaseResource::PublishResourceAd( resource_ad );

	resource_ad->Assign( ATTR_X509_USER_PROXY_SUBJECT, proxySubject );
	resource_ad->Assign( ATTR_X509_USER_PROXY_FQAN, proxyFQAN );
}

void NordugridResource::DoPing( unsigned& ping_delay, bool& ping_complete,
								bool& ping_succeeded )
{
	int rc;

	if ( gahp->isInitialized() == false ) {
		dprintf( D_ALWAYS,"gahp server not up yet, delaying ping\n" );
		ping_delay = 5;
		return;
	}
	gahp->setNormalProxy( gahp->getMasterProxy() );
	if ( PROXY_IS_EXPIRED( gahp->getMasterProxy() ) ) {
		dprintf( D_ALWAYS,"proxy near expiration or invalid, delaying ping\n" );
		ping_delay = TIMER_NEVER;
		return;
	}

	ping_delay = 0;

	rc = gahp->nordugrid_ping( resourceName );

	if ( rc == GAHPCLIENT_COMMAND_PENDING ) {
		ping_complete = false;
	} else if ( rc != 0 ) {
		ping_complete = true;
		ping_succeeded = false;
	} else {
		ping_complete = true;
		ping_succeeded = true;
	}
}

void NordugridResource::DoJobStatus()
{
	if ( ( registeredJobs.IsEmpty() || resourceDown ) &&
		 m_jobStatusActive == false ) {
			// No jobs or we can't talk to the resource, so no point
			// in polling
		daemonCore->Reset_Timer( m_jobStatusTid, m_paramJobPollInterval );
		return;
	}

	if ( m_statusGahp->isStarted() == false ) {
		// The gahp isn't started yet. Wait a few seconds for a Job
		// object to start it and initialize x509 credentials.
		daemonCore->Reset_Timer( m_jobStatusTid, 5 );
		return;
	}

	daemonCore->Reset_Timer( m_jobStatusTid, TIMER_NEVER );

	StringList results;

	if ( m_jobStatusActive == false ) {

			// start ldap status command
		dprintf( D_FULLDEBUG, "Starting ldap poll: %s\n", resourceName );

		std::string ldap_server = resourceName;
		size_t pos = ldap_server.find_first_of( ':' );
		if ( pos != std::string::npos ) {
			ldap_server.erase( pos );
		}

		std::string filter;
		formatstr( filter, "(&(objectclass=nordugrid-job)(nordugrid-job-globalowner=%s))", proxySubject );
		int rc = m_statusGahp->nordugrid_ldap_query( ldap_server.c_str(), "mds-vo-name=local,o=grid", filter.c_str(), "nordugrid-job-globalid,nordugrid-job-status",
													 results );
		if ( rc != GAHPCLIENT_COMMAND_PENDING ) {
			dprintf( D_ALWAYS,
					 "gahp->nordugrid_ldap_query returned %d for resource %s\n",
					 rc, resourceName );
			EXCEPT( "nordugrid_ldap_query failed!" );
		}
		m_jobStatusActive = true;

	} else {

			// finish ldap status command
		int rc = m_statusGahp->nordugrid_ldap_query( NULL, NULL, NULL, NULL, results );

		if ( rc == GAHPCLIENT_COMMAND_PENDING ) {
			return;
		} else if ( rc != 0 ) {
			dprintf( D_ALWAYS,
					 "gahp->nordugrid_ldap_query returned %d for resource %s: %s\n",
					 rc, resourceName, m_statusGahp->getErrorString() );
			dprintf( D_ALWAYS, "Requesting ping of resource\n" );
			RequestPing( NULL );
		}

		if ( rc == 0 ) {
			const char *next_job_id = NULL;
			const char *next_status = NULL;
			const char *next_attr;
			std::string key;

			results.rewind();
			do {
				next_attr = results.next();

				if ( next_attr != NULL && *next_attr != '\0' ) {
						// Save the attributes we're interested in
					if ( !strncmp( next_attr, "nordugrid-job-globalid: ", 24 ) ) {
						next_job_id = next_attr;
					} else if ( !strncmp( next_attr, "nordugrid-job-status: ", 22 ) ) {
						next_status = next_attr;
					}
					continue;
				}
					// We just reached the end of a record. Process it.
					// If we don't have the attributes we expect, skip it.
				if ( next_job_id && next_status ) {
					int rc2;
					NordugridJob *job;
					formatstr( key, "nordugrid %s %s", resourceName,
							 strrchr( next_job_id, '/' ) + 1 );
					rc2 = BaseJob::JobsByRemoteId.lookup( HashKey( key.c_str() ),
														  (BaseJob*&)job );
					if ( rc2 == 0 ) {
						job->NotifyNewRemoteStatus( strchr( next_status, ' ' ) + 1 );
					}
				}
				next_job_id = NULL;
				next_status = NULL;
			} while ( next_attr );

		}

		m_jobStatusActive = false;

		dprintf( D_FULLDEBUG, "ldap poll complete: %s\n", resourceName );

		daemonCore->Reset_Timer( m_jobStatusTid, m_paramJobPollInterval );
	}
}
<commit_msg>Fix g++ warning on Fedora 24.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

#include "condor_common.h"
#include "condor_config.h"
#include "string_list.h"

#include "nordugridresource.h"
#include "nordugridjob.h"
#include "gridmanager.h"

#define HASH_TABLE_SIZE			500

HashTable <HashKey, NordugridResource *>
    NordugridResource::ResourcesByName( HASH_TABLE_SIZE,
										hashFunction );

const char *NordugridResource::HashName( const char *resource_name,
										 const char *proxy_subject )
{
	static std::string hash_name;

	formatstr( hash_name, "nordugrid %s#%s", resource_name,
					   proxy_subject ? proxy_subject : "NULL" );

	return hash_name.c_str();
}

NordugridResource *NordugridResource::FindOrCreateResource( const char * resource_name,
															const Proxy *proxy )
{
	int rc;
	NordugridResource *resource = NULL;

	rc = ResourcesByName.lookup( HashKey( HashName( resource_name,
													proxy->subject->fqan ) ),
								 resource );
	if ( rc != 0 ) {
		resource = new NordugridResource( resource_name, proxy );
		ASSERT(resource);
		resource->Reconfig();
		ResourcesByName.insert( HashKey( HashName( resource_name,
												   proxy->subject->fqan ) ),
								resource );
	} else {
		ASSERT(resource);
	}

	return resource;
}

NordugridResource::NordugridResource( const char *resource_name,
									  const Proxy *proxy )
	: BaseResource( resource_name )
{
	proxySubject = strdup( proxy->subject->subject_name );
	proxyFQAN = strdup( proxy->subject->fqan );

	gahp = NULL;

	std::string buff;
	formatstr( buff, "NORDUGRID/%s", proxyFQAN );

	gahp = new GahpClient( buff.c_str() );
	gahp->setNotificationTimerId( pingTimerId );
	gahp->setMode( GahpClient::normal );
	gahp->setTimeout( NordugridJob::gahpCallTimeout );

	m_jobStatusTid = daemonCore->Register_Timer( 0,
							(TimerHandlercpp)&NordugridResource::DoJobStatus,
							"NordugridResource::DoJobStatus", (Service*)this );

	m_statusGahp = new GahpClient( buff.c_str() );
	m_statusGahp->setNotificationTimerId( m_jobStatusTid );
	m_statusGahp->setMode( GahpClient::normal );
	m_statusGahp->setTimeout( NordugridJob::gahpCallTimeout );

	m_jobStatusActive = false;
}

NordugridResource::~NordugridResource()
{
	ResourcesByName.remove( HashKey( HashName( resourceName, proxyFQAN ) ) );
	free( proxyFQAN );
	if ( proxySubject ) {
		free( proxySubject );
	}
	if ( gahp ) {
		delete gahp;
	}
	delete m_statusGahp;
	if ( m_jobStatusTid != TIMER_UNSET ) {
		daemonCore->Cancel_Timer( m_jobStatusTid );
	}
}

void NordugridResource::Reconfig()
{
	BaseResource::Reconfig();

	gahp->setTimeout( NordugridJob::gahpCallTimeout );
}

const char *NordugridResource::ResourceType()
{
	return "nordugrid";
}

const char *NordugridResource::GetHashName()
{
	return HashName( resourceName, proxyFQAN );
}

void NordugridResource::PublishResourceAd( ClassAd *resource_ad )
{
	BaseResource::PublishResourceAd( resource_ad );

	resource_ad->Assign( ATTR_X509_USER_PROXY_SUBJECT, proxySubject );
	resource_ad->Assign( ATTR_X509_USER_PROXY_FQAN, proxyFQAN );
}

void NordugridResource::DoPing( unsigned& ping_delay, bool& ping_complete,
								bool& ping_succeeded )
{
	int rc;

	if ( gahp->isInitialized() == false ) {
		dprintf( D_ALWAYS,"gahp server not up yet, delaying ping\n" );
		ping_delay = 5;
		return;
	}
	gahp->setNormalProxy( gahp->getMasterProxy() );
	if ( PROXY_IS_EXPIRED( gahp->getMasterProxy() ) ) {
		dprintf( D_ALWAYS,"proxy near expiration or invalid, delaying ping\n" );
		ping_delay = TIMER_NEVER;
		return;
	}

	ping_delay = 0;

	rc = gahp->nordugrid_ping( resourceName );

	if ( rc == GAHPCLIENT_COMMAND_PENDING ) {
		ping_complete = false;
	} else if ( rc != 0 ) {
		ping_complete = true;
		ping_succeeded = false;
	} else {
		ping_complete = true;
		ping_succeeded = true;
	}
}

void NordugridResource::DoJobStatus()
{
	if ( ( registeredJobs.IsEmpty() || resourceDown ) &&
		 m_jobStatusActive == false ) {
			// No jobs or we can't talk to the resource, so no point
			// in polling
		daemonCore->Reset_Timer( m_jobStatusTid, m_paramJobPollInterval );
		return;
	}

	if ( m_statusGahp->isStarted() == false ) {
		// The gahp isn't started yet. Wait a few seconds for a Job
		// object to start it and initialize x509 credentials.
		daemonCore->Reset_Timer( m_jobStatusTid, 5 );
		return;
	}

	daemonCore->Reset_Timer( m_jobStatusTid, TIMER_NEVER );

	StringList results;

	if ( m_jobStatusActive == false ) {

			// start ldap status command
		dprintf( D_FULLDEBUG, "Starting ldap poll: %s\n", resourceName );

		std::string ldap_server = resourceName;
		size_t pos = ldap_server.find_first_of( ':' );
		if ( pos != std::string::npos ) {
			ldap_server.erase( pos );
		}

		std::string filter;
		formatstr( filter, "(&(objectclass=nordugrid-job)(nordugrid-job-globalowner=%s))", proxySubject );
		int rc = m_statusGahp->nordugrid_ldap_query( ldap_server.c_str(), "mds-vo-name=local,o=grid", filter.c_str(), "nordugrid-job-globalid,nordugrid-job-status",
													 results );
		if ( rc != GAHPCLIENT_COMMAND_PENDING ) {
			dprintf( D_ALWAYS,
					 "gahp->nordugrid_ldap_query returned %d for resource %s\n",
					 rc, resourceName );
			EXCEPT( "nordugrid_ldap_query failed!" );
		}
		m_jobStatusActive = true;

	} else {

			// finish ldap status command
		int rc = m_statusGahp->nordugrid_ldap_query( NULL, NULL, NULL, NULL, results );

		if ( rc == GAHPCLIENT_COMMAND_PENDING ) {
			return;
		} else if ( rc != 0 ) {
			dprintf( D_ALWAYS,
					 "gahp->nordugrid_ldap_query returned %d for resource %s: %s\n",
					 rc, resourceName, m_statusGahp->getErrorString() );
			dprintf( D_ALWAYS, "Requesting ping of resource\n" );
			RequestPing( NULL );
		}

		if ( rc == 0 ) {
			const char *next_job_id = NULL;
			const char *next_status = NULL;
			const char *next_attr;
			std::string key;

			results.rewind();
			do {
				next_attr = results.next();

				if ( next_attr != NULL && *next_attr != '\0' ) {
						// Save the attributes we're interested in
					if ( !strncmp( next_attr, "nordugrid-job-globalid: ", 24 ) ) {
						next_job_id = next_attr;
					} else if ( !strncmp( next_attr, "nordugrid-job-status: ", 22 ) ) {
						next_status = next_attr;
					}
					continue;
				}
					// We just reached the end of a record. Process it.
					// If we don't have the attributes we expect, skip it.
				if ( next_job_id && next_status ) {
					int rc2;
					formatstr( key, "nordugrid %s %s", resourceName,
							 strrchr( next_job_id, '/' ) + 1 );
					BaseJob *base_job = NULL;
					NordugridJob *job = NULL;
					rc2 = BaseJob::JobsByRemoteId.lookup( HashKey( key.c_str() ),
														  base_job );
					if ( rc2 == 0 && (job = dynamic_cast<NordugridJob*>(base_job)) ) {
						job->NotifyNewRemoteStatus( strchr( next_status, ' ' ) + 1 );
					}
				}
				next_job_id = NULL;
				next_status = NULL;
			} while ( next_attr );

		}

		m_jobStatusActive = false;

		dprintf( D_FULLDEBUG, "ldap poll complete: %s\n", resourceName );

		daemonCore->Reset_Timer( m_jobStatusTid, m_paramJobPollInterval );
	}
}
<|endoftext|>