Merge branch 'master' of github.com:jthornber/thin-provisioning-tools

This commit is contained in:
Joe Thornber 2015-04-13 16:57:14 +01:00
commit 9de2b26c25
35 changed files with 850 additions and 138 deletions

View File

@ -1,3 +1,8 @@
v0.5
====
- thin_delta, thin_trim
v0.4
====

View File

@ -29,6 +29,7 @@ SOURCE=\
base/base64.cc \
base/endian_utils.cc \
base/error_state.cc \
base/error_string.cc \
base/progress_monitor.cc \
base/xml_utils.cc \
block-cache/block_cache.cc \
@ -86,6 +87,7 @@ SOURCE=\
thin-provisioning/thin_repair.cc \
thin-provisioning/thin_restore.cc \
thin-provisioning/thin_rmap.cc \
thin-provisioning/thin_trim.cc \
thin-provisioning/xml_format.cc
CC:=@CC@
@ -97,6 +99,7 @@ CFLAGS+=-g -Wall -O3
CXXFLAGS+=-g -Wall -fno-strict-aliasing
CXXFLAGS+=@CXXOPTIMISE_FLAG@
CXXFLAGS+=@CXXDEBUG_FLAG@
CXXFLAGS+=@CXX_STRERROR_FLAG@
INCLUDES+=-I$(TOP_BUILDDIR) -I$(TOP_DIR) -I$(TOP_DIR)/thin-provisioning
LIBS:=-lstdc++ -laio -lexpat
INSTALL:=@INSTALL@
@ -167,10 +170,12 @@ install: bin/pdata_tools
ln -s -f pdata_tools $(BINDIR)/cache_repair
ln -s -f pdata_tools $(BINDIR)/cache_restore
ln -s -f pdata_tools $(BINDIR)/thin_check
ln -s -f pdata_tools $(BINDIR)/thin_delta
ln -s -f pdata_tools $(BINDIR)/thin_dump
ln -s -f pdata_tools $(BINDIR)/thin_repair
ln -s -f pdata_tools $(BINDIR)/thin_restore
ln -s -f pdata_tools $(BINDIR)/thin_rmap
ln -s -f pdata_tools $(BINDIR)/thin_trim
ln -s -f pdata_tools $(BINDIR)/thin_metadata_size
ln -s -f pdata_tools $(BINDIR)/era_check
ln -s -f pdata_tools $(BINDIR)/era_dump
@ -182,10 +187,12 @@ install: bin/pdata_tools
$(INSTALL_DATA) man8/cache_repair.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/cache_restore.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_delta.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_repair.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_restore.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_rmap.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_trim.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/thin_metadata_size.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/era_check.8 $(MANPATH)/man8
$(INSTALL_DATA) man8/era_dump.8 $(MANPATH)/man8

View File

@ -1,5 +1,6 @@
#include "base/application.h"
#include <libgen.h>
#include <linux/limits.h>
#include <string.h>
@ -11,7 +12,7 @@ using namespace std;
int
application::run(int argc, char **argv)
{
string cmd = basename(argv[0]);
string cmd = get_basename(argv[0]);
if (cmd == string("pdata_tools")) {
argc--;
@ -49,7 +50,7 @@ application::usage()
}
std::string
application::basename(std::string const &path) const
application::get_basename(std::string const &path) const
{
char buffer[PATH_MAX + 1];

View File

@ -41,7 +41,7 @@ namespace base {
private:
void usage();
std::string basename(std::string const &path) const;
std::string get_basename(std::string const &path) const;
std::list<command const *> cmds_;
};

View File

@ -25,6 +25,26 @@
//----------------------------------------------------------------
/* An old glic doesn't provide these macros */
#if !defined(htole16) || !defined(le16toh) || !defined(htole32) || !defined(le32toh) || !defined(htole64) || !defined(le64toh)
#include <byteswap.h>
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define htole16(x) (x)
#define le16toh(x) (x)
#define htole32(x) (x)
#define le32toh(x) (x)
#define htole64(x) (x)
#define le64toh(x) (x)
#else
#define htole16(x) __bswap_16(x)
#define le16toh(x) __bswap_16(x)
#define htole32(x) __bswap_32(x)
#define le32toh(x) __bswap_32(x)
#define htole64(x) __bswap_64(x)
#define le64toh(x) __bswap_64(x)
#endif
#endif
namespace base {
// These are just little wrapper types to make the compiler

View File

@ -11,6 +11,11 @@ namespace base {
};
error_state combine_errors(error_state lhs, error_state rhs);
inline error_state &operator <<(error_state &err, error_state rhs) {
err = combine_errors(err, rhs);
return err;
}
}
//----------------------------------------------------------------

39
base/error_string.cc Normal file
View File

@ -0,0 +1,39 @@
#include "base/error_string.h"
#include <errno.h>
#include <stdexcept>
#include <string.h>
using namespace std;
//----------------------------------------------------------------
#ifdef STRERROR_R_CHAR_P
string base::error_string(int err)
{
char *ptr;
char buffer[128];
ptr = strerror_r(errno, buffer, sizeof(buffer));
return string(ptr);
}
#else
string base::error_string(int err)
{
int r;
char buffer[128];
r = strerror_r(errno, buffer, sizeof(buffer));
if (r)
throw runtime_error("strerror_r failed");
return string(buffer);
}
#endif
//----------------------------------------------------------------

16
base/error_string.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef BASE_ERROR_STRING_H
#define BASE_ERROR_STRING_H
#include <string>
//----------------------------------------------------------------
namespace base {
// There are a couple of version of strerror_r kicking around, so
// we wrap it.
std::string error_string(int err);
}
//----------------------------------------------------------------
#endif

View File

@ -13,6 +13,7 @@
#include <unistd.h>
#include "base/error_state.h"
#include "base/error_string.h"
#include "base/nested_output.h"
#include "caching/commands.h"
#include "caching/metadata.h"
@ -202,10 +203,7 @@ namespace {
int r = ::stat(path.c_str(), &info);
if (r) {
ostringstream msg;
char buffer[128], *ptr;
ptr = ::strerror_r(errno, buffer, sizeof(buffer));
msg << path << ": " << ptr;
msg << path << ": " << error_string(errno);
throw runtime_error(msg.str());
}

View File

@ -38,16 +38,16 @@ namespace {
xx(4);
template <uint32_t WIDTH>
shared_ptr<array_base> mk_array(transaction_manager &tm) {
boost::shared_ptr<array_base> mk_array(transaction_manager &tm) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<array_base> r = typename ha::ptr(new ha(tm, typename traits::ref_counter()));
boost::shared_ptr<array_base> r = typename ha::ptr(new ha(tm, typename traits::ref_counter()));
return r;
}
shared_ptr<array_base> mk_array(transaction_manager &tm, uint32_t width) {
boost::shared_ptr<array_base> mk_array(transaction_manager &tm, uint32_t width) {
switch (width) {
#define xx(n) case n: return mk_array<n>(tm)
@ -58,15 +58,15 @@ namespace {
}
// never get here
return shared_ptr<array_base>();
return boost::shared_ptr<array_base>();
}
//--------------------------------
template <typename HA>
shared_ptr<HA>
downcast_array(shared_ptr<array_base> base) {
shared_ptr<HA> a = dynamic_pointer_cast<HA>(base);
boost::shared_ptr<HA>
downcast_array(boost::shared_ptr<array_base> base) {
boost::shared_ptr<HA> a = dynamic_pointer_cast<HA>(base);
if (!a)
throw runtime_error("internal error: couldn't cast hint array");
@ -76,16 +76,16 @@ namespace {
//--------------------------------
template <uint32_t WIDTH>
shared_ptr<array_base> mk_array(transaction_manager &tm, block_address root, unsigned nr_entries) {
boost::shared_ptr<array_base> mk_array(transaction_manager &tm, block_address root, unsigned nr_entries) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<array_base> r = typename ha::ptr(new ha(tm, typename traits::ref_counter(), root, nr_entries));
boost::shared_ptr<array_base> r = typename ha::ptr(new ha(tm, typename traits::ref_counter(), root, nr_entries));
return r;
}
shared_ptr<array_base> mk_array(transaction_manager &tm, uint32_t width, block_address root, unsigned nr_entries) {
boost::shared_ptr<array_base> mk_array(transaction_manager &tm, uint32_t width, block_address root, unsigned nr_entries) {
switch (width) {
#define xx(n) case n: return mk_array<n>(tm, root, nr_entries)
all_widths
@ -95,21 +95,21 @@ namespace {
}
// never get here
return shared_ptr<array_base>();
return boost::shared_ptr<array_base>();
}
//--------------------------------
template <uint32_t WIDTH>
void get_hint(shared_ptr<array_base> base, unsigned index, vector<unsigned char> &data) {
void get_hint(boost::shared_ptr<array_base> base, unsigned index, vector<unsigned char> &data) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<ha> a = downcast_array<ha>(base);
boost::shared_ptr<ha> a = downcast_array<ha>(base);
data = a->get(index);
}
void get_hint_(uint32_t width, shared_ptr<array_base> base, unsigned index, vector<unsigned char> &data) {
void get_hint_(uint32_t width, boost::shared_ptr<array_base> base, unsigned index, vector<unsigned char> &data) {
switch (width) {
#define xx(n) case n: return get_hint<n>(base, index, data)
all_widths
@ -120,15 +120,15 @@ namespace {
//--------------------------------
template <uint32_t WIDTH>
void set_hint(shared_ptr<array_base> base, unsigned index, vector<unsigned char> const &data) {
void set_hint(boost::shared_ptr<array_base> base, unsigned index, vector<unsigned char> const &data) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<ha> a = downcast_array<ha>(base);
boost::shared_ptr<ha> a = downcast_array<ha>(base);
a->set(index, data);
}
void set_hint_(uint32_t width, shared_ptr<array_base> base,
void set_hint_(uint32_t width, boost::shared_ptr<array_base> base,
unsigned index, vector<unsigned char> const &data) {
switch (width) {
#define xx(n) case n: return set_hint<n>(base, index, data)
@ -140,15 +140,15 @@ namespace {
//--------------------------------
template <uint32_t WIDTH>
void grow(shared_ptr<array_base> base, unsigned new_nr_entries, vector<unsigned char> const &value) {
void grow(boost::shared_ptr<array_base> base, unsigned new_nr_entries, vector<unsigned char> const &value) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<ha> a = downcast_array<ha>(base);
boost::shared_ptr<ha> a = downcast_array<ha>(base);
a->grow(new_nr_entries, value);
}
void grow_(uint32_t width, shared_ptr<array_base> base,
void grow_(uint32_t width, boost::shared_ptr<array_base> base,
unsigned new_nr_entries, vector<unsigned char> const &value)
{
switch (width) {
@ -194,17 +194,17 @@ namespace {
};
template <uint32_t WIDTH>
void walk_hints(shared_ptr<array_base> base, hint_visitor &hv, damage_visitor &dv) {
void walk_hints(boost::shared_ptr<array_base> base, hint_visitor &hv, damage_visitor &dv) {
typedef hint_traits<WIDTH> traits;
typedef array<traits> ha;
typedef persistent_data::array<traits> ha;
shared_ptr<ha> a = downcast_array<ha>(base);
boost::shared_ptr<ha> a = downcast_array<ha>(base);
value_adapter vv(hv);
ll_damage_visitor ll(dv);
a->visit_values(vv, ll);
}
void walk_hints_(uint32_t width, shared_ptr<array_base> base,
void walk_hints_(uint32_t width, boost::shared_ptr<array_base> base,
hint_visitor &hv, damage_visitor &dv) {
switch (width) {
#define xx(n) case n: walk_hints<n>(base, hv, dv); break

View File

@ -302,8 +302,9 @@ namespace validator {
superblock
caching::read_superblock(block_manager<>::ptr bm, block_address location)
{
using namespace validator;
superblock sb;
block_manager<>::read_ref r = bm->read_lock(location, validator::mk_v());
block_manager<>::read_ref r = bm->read_lock(location, mk_v());
superblock_disk const *sbd = reinterpret_cast<superblock_disk const *>(r.data());
superblock_traits::unpack(*sbd, sb);
@ -313,7 +314,8 @@ caching::read_superblock(block_manager<>::ptr bm, block_address location)
void
caching::write_superblock(block_manager<>::ptr bm, superblock const &sb, block_address location)
{
block_manager<>::write_ref w = bm->superblock_zero(location, validator::mk_v());
using namespace validator;
block_manager<>::write_ref w = bm->superblock_zero(location, mk_v());
superblock_traits::pack(sb, *reinterpret_cast<superblock_disk *>(w.data()));
}

View File

@ -42,6 +42,13 @@ AC_PROG_MAKE_SET
AC_PROG_MKDIR_P
AC_PROG_INSTALL
################################################################
dnl -- Checks for functions.
AC_FUNC_STRERROR_R
if test x$ac_cv_func_strerror_r_char_p = xyes; then
CXX_STRERROR_FLAG="-DSTRERROR_R_CHAR_P"
fi
################################################################################
dnl -- Prefix is /usr by default, the exec_prefix default is setup later
AC_PREFIX_DEFAULT(/usr)
@ -136,6 +143,7 @@ VERSION_PATCHLEVEL=`echo "$VER" | $AWK -F '[[(.]]' '{print $3}'`
################################################################
AC_SUBST(CXXDEBUG_FLAG)
AC_SUBST(CXXOPTIMISE_FLAG)
AC_SUBST(CXX_STRERROR_FLAG)
AC_SUBST(INSTALL)
AC_SUBST(prefix)
AC_SUBST(RELEASE_DATE)

View File

@ -13,6 +13,7 @@
#include <unistd.h>
#include "base/error_state.h"
#include "base/error_string.h"
#include "base/nested_output.h"
#include "era/commands.h"
#include "era/writeset_tree.h"
@ -186,10 +187,7 @@ namespace {
int r = ::stat(path.c_str(), &info);
if (r) {
ostringstream msg;
char buffer[128], *ptr;
ptr = ::strerror_r(errno, buffer, sizeof(buffer));
msg << path << ": " << ptr;
msg << path << ": " << error_string(errno);;
throw runtime_error(msg.str());
}

47
man8/thin_delta.8 Normal file
View File

@ -0,0 +1,47 @@
.TH THIN_DELTA 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*-
.SH NAME
thin_delta \- Print the differences in the mappings between two thin devices.
.SH SYNOPSIS
.B thin_delta
.RB [ options ]
.I {device|file}
.SH DESCRIPTION
.B thin_delta
allows you to compare the mappings in two thin volumes (snapshots allow common blocks between thin volumes).
.
.SH OPTIONS
.IP "\fB\-\-thin1, \-\-snap1\fP"
The numeric identifier for the first thin volume to diff.
.IP "\fB\-\-thin1, \-\-snap1\fP"
The numeric identifier for the second thin volume to diff.
.IP "\fB\-m, \-\-metadata\-snap\fP [block#]"
If you want to get information out of a live pool then you will need
to take a metadata snapshot and use this switch. In order for the
information to be meaningful you need to ensure the thin volumes
you're examining are not changing (eg, do not activate those thins).
.IP "\fB\-\-verbose"
Provide extra information on the mappings.
.IP "\fB\-h, \-\-help\fP"
Print help and exit.
.IP "\fB\-V, \-\-version\fP"
Output version information and exit.
.SH SEE ALSO
.B thin_dump(8)
.B thin_repair(8)
.B thin_restore(8)
.B thin_rmap(8)
.B thin_trim(8)
.B thin_metadata_size(8)
.SH AUTHOR
Joe Thornber <ejt@redhat.com>

34
man8/thin_trim.8 Normal file
View File

@ -0,0 +1,34 @@
.TH THIN_TRIM 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*-
.SH NAME
thin_trim \- Issue discard requests for free pool space (offline tool).
.SH SYNOPSIS
.B thin_trim
.RB [ options ]
.I {device|file}
.SH DESCRIPTION
.B thin_trim
sends discard requests to the pool device for unprovisioned areas. It is an offline tool,
.B do not run it while the pool is active
.
.SH OPTIONS
.IP "\fB\-\-pool-inactive\fP"
Indicates you are aware the pool should be inactive. Suppresses a warning message and prompt.
.IP "\fB\-h, \-\-help\fP"
Print help and exit.
.IP "\fB\-V, \-\-version\fP"
Output version information and exit.
.SH SEE ALSO
.B thin_dump(8)
.B thin_repair(8)
.B thin_restore(8)
.B thin_rmap(8)
.B thin_metadata_size(8)
.SH AUTHOR
Joe Thornber <ejt@redhat.com>

View File

@ -18,13 +18,14 @@
#include "block.h"
#include "base/error_string.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <boost/bind.hpp>
#include <stdexcept>
@ -44,11 +45,8 @@ namespace {
// FIXME: introduce a new exception for this, or at least lift this
// to exception.h
void syscall_failed(char const *call) {
char buffer[128];
char *msg = strerror_r(errno, buffer, sizeof(buffer));
ostringstream out;
out << "syscall '" << call << "' failed: " << msg;
out << "syscall '" << call << "' failed: " << base::error_string(errno);;
throw runtime_error(out.str());
}

View File

@ -286,23 +286,8 @@ namespace persistent_data {
}
}
//--------------------------------
struct ablock_counter {
ablock_counter(block_counter &bc)
: bc_(bc) {
}
void visit(btree_detail::node_location const &loc, block_address b) {
bc_.inc(b);
}
private:
block_counter &bc_;
};
void count_metadata_blocks(block_counter &bc) const {
ablock_counter vc(bc);
block_address_counter vc(bc);
count_btree_blocks(block_tree_, bc, vc);
}

View File

@ -7,7 +7,7 @@ using namespace persistent_data;
//----------------------------------------------------------------
namespace {
static const uint64_t m1 = 0x9e37fffffffc0001UL;
static const uint64_t m1 = 0x9e37fffffffc0001ULL;
static const unsigned bits = 18;
static uint32_t hash1(block_address const &b) {

View File

@ -1,6 +1,7 @@
#ifndef PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H
#define PERSISTENT_DATA_DATA_STRUCTURES_BTREE_COUNTER_H
#include "persistent-data/data-structures/btree.h"
#include "persistent-data/block_counter.h"
//----------------------------------------------------------------
@ -65,6 +66,19 @@ namespace persistent_data {
}
};
struct block_address_counter {
block_address_counter(block_counter &bc)
: bc_(bc) {
}
void visit(btree_detail::node_location const &loc, block_address b) {
bc_.inc(b);
}
private:
block_counter &bc_;
};
// Counts how many times each metadata block is referenced in the
// tree. Blocks already referenced in the block counter are not
// walked. This walk should only be done once you're sure the tree

View File

@ -89,6 +89,10 @@ namespace {
sm_->iterate(it);
}
virtual void count_metadata(block_counter &bc) const {
sm_->count_metadata(bc);
}
virtual size_t root_size() const {
return sm_->root_size();
}

View File

@ -105,6 +105,9 @@ namespace persistent_data {
throw std::runtime_error("'extend' not implemented");
}
void count_metadata(block_counter &bc) const {
}
// FIXME: meaningless, but this class is only used for testing
size_t root_size() const {
return 0;

View File

@ -24,6 +24,7 @@
#include "persistent-data/space-maps/careful_alloc.h"
#include "persistent-data/data-structures/btree_damage_visitor.h"
#include "persistent-data/data-structures/btree_counter.h"
#include "persistent-data/checksum.h"
#include "persistent-data/math_utils.h"
#include "persistent-data/transaction_manager.h"
@ -112,7 +113,7 @@ namespace {
ref_t b1 = test_bit_le(bits, b * 2);
ref_t b2 = test_bit_le(bits, b * 2 + 1);
ref_t result = b2 ? 1 : 0;
result |= b1 ? 0b10 : 0;
result |= b1 ? 2 : 0;
return result;
}
@ -165,7 +166,7 @@ namespace {
ref_t b1 = test_bit_le(bits, b * 2);
ref_t b2 = test_bit_le(bits, b * 2 + 1);
ref_t result = b2 ? 1 : 0;
result |= b1 ? 0b10 : 0;
result |= b1 ? 2 : 0;
it(offset + b, result);
}
}
@ -223,6 +224,7 @@ namespace {
public:
typedef boost::shared_ptr<index_store> ptr;
virtual void count_metadata(block_counter &bc) const = 0;
virtual void resize(block_address nr_indexes) = 0;
virtual index_entry find_ie(block_address b) const = 0;
virtual void save_ie(block_address b, struct index_entry ie) = 0;
@ -406,6 +408,13 @@ namespace {
}
}
virtual void count_metadata(block_counter &bc) const {
indexes_->count_metadata(bc);
noop_value_counter<uint32_t> vc;
count_btree_blocks(ref_counts_, bc, vc);
}
virtual size_t root_size() const {
return sizeof(sm_root_disk);
}
@ -555,6 +564,29 @@ namespace {
bitmaps_(tm, root, index_entry_traits::ref_counter()) {
}
//--------------------------------
struct index_entry_counter {
index_entry_counter(block_counter &bc)
: bc_(bc) {
}
void visit(btree_detail::node_location const &loc, index_entry const &ie) {
if (ie.blocknr_ != 0)
bc_.inc(ie.blocknr_);
}
private:
block_counter &bc_;
};
virtual void count_metadata(block_counter &bc) const {
index_entry_counter vc(bc);
count_btree_blocks(bitmaps_, bc, vc);
}
//--------------------------------
virtual void resize(block_address nr_entries) {
// No op
}
@ -613,6 +645,17 @@ namespace {
load_ies();
}
virtual void count_metadata(block_counter &bc) const {
bc.inc(bitmap_root_);
for (unsigned i = 0; i < entries_.size(); i++) {
block_address b = entries_[i].blocknr_;
if (b != 0)
bc.inc(b);
}
}
virtual void resize(block_address nr_indexes) {
entries_.resize(nr_indexes);
}

View File

@ -178,6 +178,10 @@ namespace {
sm_->iterate(it);
}
virtual void count_metadata(block_counter &bc) const {
sm_->count_metadata(bc);
}
virtual size_t root_size() const {
cant_recurse("root_size");
recursing_const_lock lock(*this);

View File

@ -119,6 +119,7 @@ namespace persistent_data {
namespace space_map_detail {
class damage {
public:
virtual ~damage() {}
};
@ -141,6 +142,7 @@ namespace persistent_data {
public:
typedef boost::shared_ptr<persistent_space_map> ptr;
virtual void count_metadata(block_counter &bc) const = 0;
virtual size_t root_size() const = 0;
virtual void copy_root(void *dest, size_t len) const = 0;
};

View File

@ -13,6 +13,7 @@ namespace thin_provisioning {
extern base::command thin_restore_cmd;
extern base::command thin_repair_cmd;
extern base::command thin_rmap_cmd;
extern base::command thin_trim_cmd;
extern base::command thin_metadata_size_cmd;
}

View File

@ -141,9 +141,9 @@ namespace {
}
};
class ll_damage_visitor {
class dev_tree_damage_visitor {
public:
ll_damage_visitor(damage_visitor &v)
dev_tree_damage_visitor(damage_visitor &v)
: v_(v) {
}
@ -158,14 +158,56 @@ namespace {
break;
default:
// shouldn't get here.
throw std::runtime_error("ll_damage_visitor: path too long");
throw std::runtime_error("dev_tree_damage_visitor: path too long");
}
}
private:
damage_visitor &v_;
};
class mapping_tree_damage_visitor {
public:
mapping_tree_damage_visitor(damage_visitor &v)
: v_(v) {
}
virtual void visit(btree_path const &path, btree_detail::damage const &d) {
switch (path.size()) {
case 0:
v_.visit(missing_devices(d.desc_, d.lost_keys_));
break;
default:
throw std::runtime_error("mapping_tree_damage_visitor: path too long");
}
}
private:
damage_visitor &v_;
};
class single_mapping_tree_damage_visitor {
public:
single_mapping_tree_damage_visitor(damage_visitor &v)
: v_(v) {
}
virtual void visit(btree_path const &path, btree_detail::damage const &d) {
switch (path.size()) {
case 0:
v_.visit(missing_mappings(d.desc_, path[0], d.lost_keys_));
break;
default:
throw std::runtime_error("single_mapping_tree_damage_visitor: path too long");
}
}
private:
damage_visitor &v_;
};
}
void
@ -173,7 +215,7 @@ thin_provisioning::walk_mapping_tree(dev_tree const &tree,
mapping_tree_detail::device_visitor &dev_v,
mapping_tree_detail::damage_visitor &dv)
{
ll_damage_visitor ll_dv(dv);
dev_tree_damage_visitor ll_dv(dv);
btree_visit_values(tree, dev_v, ll_dv);
}
@ -190,7 +232,7 @@ thin_provisioning::walk_mapping_tree(mapping_tree const &tree,
mapping_tree_detail::mapping_visitor &mv,
mapping_tree_detail::damage_visitor &dv)
{
ll_damage_visitor ll_dv(dv);
mapping_tree_damage_visitor ll_dv(dv);
btree_visit_values(tree, mv, ll_dv);
}
@ -207,7 +249,7 @@ thin_provisioning::walk_mapping_tree(single_mapping_tree const &tree,
mapping_tree_detail::mapping_visitor &mv,
mapping_tree_detail::damage_visitor &dv)
{
ll_damage_visitor ll_dv(dv);
single_mapping_tree_damage_visitor ll_dv(dv);
btree_visit_values(tree, mv, ll_dv);
}

View File

@ -54,6 +54,9 @@ namespace thin_provisioning {
transaction_manager::ptr tm_;
};
// This value type is itself a tree containing mappings.
// Used when manipulating the top level of the mapping
// tree.
struct mtree_traits {
typedef base::le64 disk_type;
typedef uint64_t value_type;

View File

@ -25,7 +25,9 @@
#include "base/application.h"
#include "base/error_state.h"
#include "base/nested_output.h"
#include "persistent-data/data-structures/btree_counter.h"
#include "persistent-data/space-maps/core.h"
#include "persistent-data/space-maps/disk.h"
#include "persistent-data/file_utils.h"
#include "thin-provisioning/device_tree.h"
#include "thin-provisioning/mapping_tree.h"
@ -39,8 +41,6 @@ using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
//--------------------------------
block_manager<>::ptr
open_bm(string const &path) {
block_address nr_blocks = get_nr_blocks(path);
@ -71,7 +71,7 @@ namespace {
nested_output::nest _ = out_.push();
out_ << d.desc_ << end_message();
}
err_ = combine_errors(err_, FATAL);
err_ << FATAL;
}
base::error_state get_error() const {
@ -99,7 +99,7 @@ namespace {
out_ << d.desc_ << end_message();
}
err_ = combine_errors(err_, FATAL);
err_ << FATAL;
}
error_state get_error() const {
@ -126,7 +126,7 @@ namespace {
nested_output::nest _ = out_.push();
out_ << d.desc_ << end_message();
}
err_ = combine_errors(err_, FATAL);
err_ << FATAL;
}
virtual void visit(mapping_tree_detail::missing_mappings const &d) {
@ -135,7 +135,7 @@ namespace {
nested_output::nest _ = out_.push();
out_ << d.desc_ << end_message();
}
err_ = combine_errors(err_, FATAL);
err_ << FATAL;
}
error_state get_error() const {
@ -169,6 +169,77 @@ namespace {
bool clear_needs_check_flag_on_success;
};
error_state check_space_map_counts(flags const &fs, nested_output &out,
superblock_detail::superblock &sb,
block_manager<>::ptr bm,
transaction_manager::ptr tm) {
block_counter bc;
// Count the superblock
bc.inc(superblock_detail::SUPERBLOCK_LOCATION);
// Count the metadata snap, if present
if (sb.metadata_snap_ != superblock_detail::SUPERBLOCK_LOCATION) {
bc.inc(sb.metadata_snap_);
superblock_detail::superblock snap = read_superblock(bm, sb.metadata_snap_);
bc.inc(snap.data_mapping_root_);
bc.inc(snap.device_details_root_);
}
// Count the device tree
{
noop_value_counter<device_tree_detail::device_details> vc;
device_tree dtree(*tm, sb.device_details_root_,
device_tree_detail::device_details_traits::ref_counter());
count_btree_blocks(dtree, bc, vc);
}
// Count the mapping tree
{
noop_value_counter<mapping_tree_detail::block_time> vc;
mapping_tree mtree(*tm, sb.data_mapping_root_,
mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
count_btree_blocks(mtree, bc, vc);
}
// Count the metadata space map
{
persistent_space_map::ptr metadata_sm =
open_metadata_sm(*tm, static_cast<void *>(&sb.metadata_space_map_root_));
metadata_sm->count_metadata(bc);
}
// Count the data space map
{
persistent_space_map::ptr data_sm =
open_disk_sm(*tm, static_cast<void *>(&sb.data_space_map_root_));
data_sm->count_metadata(bc);
}
// Finally we need to check the metadata space map agrees
// with the counts we've just calculated.
error_state err = NO_ERROR;
nested_output::nest _ = out.push();
persistent_space_map::ptr metadata_sm =
open_metadata_sm(*tm, static_cast<void *>(&sb.metadata_space_map_root_));
for (unsigned b = 0; b < metadata_sm->get_nr_blocks(); b++) {
ref_t c_actual = metadata_sm->get_count(b);
ref_t c_expected = bc.get_count(b);
if (c_actual != c_expected) {
out << "metadata reference counts differ for block " << b
<< ", expected " << c_expected
<< ", but got " << c_actual
<< end_message();
err << (c_actual > c_expected ? NON_FATAL : FATAL);
}
}
return err;
}
error_state metadata_check(string const &path, flags fs) {
block_manager<>::ptr bm = open_bm(path);
@ -221,9 +292,17 @@ namespace {
}
}
return combine_errors(sb_rep.get_error(),
combine_errors(mapping_rep.get_error(),
dev_rep.get_error()));
error_state err = NO_ERROR;
err << sb_rep.get_error() << mapping_rep.get_error() << dev_rep.get_error();
// if we're checking everything, and there were no errors,
// then we should check the space maps too.
if (fs.check_device_tree && fs.check_mapping_tree_level2 && err != FATAL) {
out << "checking space map counts" << end_message();
err << check_space_map_counts(fs, out, sb, bm, tm);
}
return err;
}
void clear_needs_check(string const &path) {

View File

@ -6,9 +6,11 @@
#include "version.h"
#include "base/indented_stream.h"
#include "persistent-data/data-structures/btree_damage_visitor.h"
#include "persistent-data/run.h"
#include "persistent-data/space-maps/core.h"
#include "persistent-data/space-maps/disk.h"
#include "persistent-data/file_utils.h"
#include "thin-provisioning/superblock.h"
#include "thin-provisioning/mapping_tree.h"
@ -27,8 +29,11 @@ namespace local {
}
void usage(ostream &out) {
out << "Usage: " << cmd_ << " [options] --snap1 <snap> --snap2 <snap> <device or file>\n"
out << "Usage: " << cmd_ << " [options] <device or file>\n"
<< "Options:\n"
<< " {--thin1, --snap1}\n"
<< " {--thin2, --snap2}\n"
<< " {-m, --metadata-snap} [block#]\n"
<< " {--verbose}\n"
<< " {-h|--help}\n"
<< " {-V|--version}" << endl;
@ -40,13 +45,13 @@ namespace local {
exit(1);
}
uint64_t parse_snap(string const &str) {
uint64_t parse_int(string const &str, string const &desc) {
try {
return boost::lexical_cast<uint64_t>(str);
} catch (...) {
ostringstream out;
out << "Couldn't parse snapshot designator: '" << str << "'";
out << "Couldn't parse " << desc << ": '" << str << "'";
die(out.str());
}
@ -63,6 +68,7 @@ namespace local {
}
boost::optional<string> dev;
boost::optional<uint64_t> metadata_snap;
boost::optional<uint64_t> snap1;
boost::optional<uint64_t> snap2;
bool verbose;
@ -123,51 +129,63 @@ namespace local {
class mapping_recorder {
public:
mapping_recorder() {
reset_range();
no_range();
}
void visit(btree_path const &path, mapping_tree_detail::block_time const &bt) {
record(path[0], bt.block_);
}
void complete() {
if (range_in_progress()) {
push_range();
no_range();
}
}
mapping_deque const &get_mappings() const {
return mappings_;
}
private:
void reset_range() {
void no_range() {
obegin_ = oend_ = 0;
dbegin_ = dend_ = 0;
}
void record(uint64_t oblock, uint64_t dblock) {
if (obegin_ == oend_) {
// We're starting a new range
obegin_ = oblock;
oend_ = obegin_;
dbegin_ = dblock;
dend_ = dbegin_;
} else {
if (oblock != oend_ || dblock != dend_) {
// Emit the current range ...
push_mapping(obegin_, dbegin_, oend_ - obegin_);
obegin_ = oblock;
oend_ = obegin_;
dbegin_ = dblock;
dend_ = dbegin_;
}
}
void inc_range() {
oend_++;
dend_++;
}
void push_mapping(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
mappings_.push_back(mapping(vbegin, dbegin, len));
void begin_range(uint64_t oblock, uint64_t dblock) {
obegin_ = oend_ = oblock;
dbegin_ = dend_ = dblock;
inc_range();
}
bool range_in_progress() {
return oend_ != obegin_;
}
bool continues_range(uint64_t oblock, uint64_t dblock) {
return (oblock == oend_) && (dblock == dend_);
}
void push_range() {
mapping m(obegin_, dbegin_, oend_ - obegin_);
mappings_.push_back(m);
}
void record(uint64_t oblock, uint64_t dblock) {
if (!range_in_progress())
begin_range(oblock, dblock);
else if (!continues_range(oblock, dblock)) {
push_range();
begin_range(oblock, dblock);
} else
inc_range();
}
uint64_t obegin_, oend_;
@ -189,7 +207,7 @@ namespace local {
class diff_emitter {
public:
diff_emitter(ostream &out)
diff_emitter(indented_stream &out)
: out_(out) {
}
@ -200,18 +218,22 @@ namespace local {
virtual void complete() = 0;
protected:
ostream &out() {
void indent() {
out_.indent();
}
indented_stream &out() {
return out_;
}
private:
ostream &out_;
indented_stream &out_;
};
class simple_emitter : public diff_emitter {
public:
simple_emitter(ostream &out)
simple_emitter(indented_stream &out)
: diff_emitter(out) {
}
@ -260,6 +282,7 @@ namespace local {
if (!current_type_)
return;
indent();
switch (*current_type_) {
case LEFT_ONLY:
out() << "<left_only";
@ -288,27 +311,30 @@ namespace local {
class verbose_emitter : public diff_emitter {
public:
verbose_emitter(ostream &out)
verbose_emitter(indented_stream &out)
: diff_emitter(out) {
}
void left_only(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
begin_block(LEFT_ONLY);
out() << " <range begin=\"" << vbegin << "\""
indent();
out() << "<range begin=\"" << vbegin << "\""
<< " data_begin=\"" << dbegin << "\""
<< " length=\"" << len << "\"/>\n";
}
void right_only(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
begin_block(RIGHT_ONLY);
out() << " <range begin=\"" << vbegin << "\""
indent();
out() << "<range begin=\"" << vbegin << "\""
<< " data_begin=\"" << dbegin << "\""
<< " length=\"" << len << "\"/>\n";
}
void blocks_differ(uint64_t vbegin, uint64_t left_dbegin, uint64_t right_dbegin, uint64_t len) {
begin_block(DIFFER);
out() << " <range begin=\"" << vbegin << "\""
indent();
out() << "<range begin=\"" << vbegin << "\""
<< " left_data_begin=\"" << left_dbegin << "\""
<< " right_data_begin=\"" << right_dbegin << "\""
<< " length=\"" << len << "\"/>\n";
@ -316,7 +342,8 @@ namespace local {
void blocks_same(uint64_t vbegin, uint64_t dbegin, uint64_t len) {
begin_block(SAME);
out() << " <range begin=\"" << vbegin << "\""
indent();
out() << "<range begin=\"" << vbegin << "\""
<< " data_begin=\"" << dbegin << "\""
<< " length=\"" << len << "\"/>\n";
}
@ -347,6 +374,7 @@ namespace local {
}
void open(block_type t) {
indent();
switch (t) {
case LEFT_ONLY:
out() << "<left_only>\n";
@ -364,24 +392,27 @@ namespace local {
out() << "<same>\n";
break;
}
out().inc();
}
void close(block_type t) {
out().dec();
indent();
switch (t) {
case LEFT_ONLY:
out() << "</left_only>\n\n";
out() << "</left_only>\n";
break;
case RIGHT_ONLY:
out() << "</right_only>\n\n";
out() << "</right_only>\n";
break;
case DIFFER:
out() << "</different>\n\n";
out() << "</different>\n";
break;
case SAME:
out() << "</same>\n\n";
out() << "</same>\n";
break;
}
@ -437,19 +468,76 @@ namespace local {
}
}
while (left_it != left.end()) {
left_mapping = *left_it++;
if (left_mapping.len_)
e.left_only(left_mapping.vbegin_, left_mapping.dbegin_, left_mapping.len_);
}
while (right_it != right.end()) {
right_mapping = *right_it++;
if (right_mapping.len_)
e.right_only(right_mapping.vbegin_, right_mapping.dbegin_, right_mapping.len_);
}
e.complete();
}
// FIXME: duplication with xml_format
void begin_superblock(indented_stream &out,
string const &uuid,
uint64_t time,
uint64_t trans_id,
uint32_t data_block_size,
uint64_t nr_data_blocks,
boost::optional<uint64_t> metadata_snap) {
out.indent();
out << "<superblock uuid=\"" << uuid << "\""
<< " time=\"" << time << "\""
<< " transaction=\"" << trans_id << "\""
<< " data_block_size=\"" << data_block_size << "\""
<< " nr_data_blocks=\"" << nr_data_blocks;
if (metadata_snap)
out << "\" metadata_snap=\"" << *metadata_snap;
out << "\">\n";
out.inc();
}
void end_superblock(indented_stream &out) {
out.dec();
out.indent();
out << "</superblock>\n";
}
void begin_diff(indented_stream &out, uint64_t snap1, uint64_t snap2) {
out.indent();
out << "<diff left=\"" << snap1 << "\" right=\"" << snap2 << "\">\n";
out.inc();
}
void end_diff(indented_stream &out) {
out.dec();
out.indent();
out << "</diff>\n";
}
void delta_(application &app, flags const &fs) {
mapping_recorder mr1;
mapping_recorder mr2;
damage_visitor damage_v;
superblock_detail::superblock sb;
checked_space_map::ptr data_sm;
{
block_manager<>::ptr bm = open_bm(*fs.dev);
transaction_manager::ptr tm = open_tm(bm);
superblock_detail::superblock sb = read_superblock(bm);
sb = fs.metadata_snap ? read_superblock(bm, *fs.metadata_snap) : read_superblock(bm);
data_sm = open_disk_sm(*tm, static_cast<void *>(&sb.data_space_map_root_));
dev_tree dtree(*tm, sb.data_mapping_root_,
mapping_tree_detail::mtree_traits::ref_counter(tm));
@ -476,16 +564,32 @@ namespace local {
single_mapping_tree snap2(*tm, *snap2_root, mapping_tree_detail::block_traits::ref_counter(tm->get_sm()));
btree_visit_values(snap1, mr1, damage_v);
mr1.complete();
btree_visit_values(snap2, mr2, damage_v);
mr2.complete();
}
indented_stream is(cout);
begin_superblock(is, "", sb.time_,
sb.trans_id_,
sb.data_block_size_,
data_sm->get_nr_blocks(),
sb.metadata_snap_ ?
boost::optional<block_address>(sb.metadata_snap_) :
boost::optional<block_address>());
begin_diff(is, *fs.snap1, *fs.snap2);
if (fs.verbose) {
verbose_emitter e(cout);
verbose_emitter e(is);
dump_diff(mr1.get_mappings(), mr2.get_mappings(), e);
} else {
simple_emitter e(cout);
simple_emitter e(is);
dump_diff(mr1.get_mappings(), mr2.get_mappings(), e);
}
end_diff(is);
end_superblock(is);
}
int delta(application &app, flags const &fs) {
@ -512,13 +616,15 @@ int thin_delta_main(int argc, char **argv)
flags fs;
local::application app(basename(argv[0]));
char const shortopts[] = "hV";
char const shortopts[] = "hVm";
option const longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "thin1", required_argument, NULL, 1 },
{ "snap1", required_argument, NULL, 1 },
{ "thin2", required_argument, NULL, 2 },
{ "snap2", required_argument, NULL, 2 },
{ "metadata-snap", no_argument, NULL, 3 },
{ "metadata-snap", no_argument, NULL, 'm' },
{ "verbose", no_argument, NULL, 4 }
};
@ -533,15 +639,15 @@ int thin_delta_main(int argc, char **argv)
return 0;
case 1:
fs.snap1 = app.parse_snap(optarg);
fs.snap1 = app.parse_int(optarg, "thin id 1");
break;
case 2:
fs.snap2 = app.parse_snap(optarg);
fs.snap2 = app.parse_int(optarg, "thin id 2");
break;
case 3:
abort();
case 'm':
fs.metadata_snap = app.parse_int(optarg, "metadata snapshot block");
break;
case 4:

View File

@ -203,7 +203,7 @@ thin_pool::get_nr_free_data_blocks() const
return md_->data_sm_->get_nr_free();
}
sector_t
thin_provisioning::sector_t
thin_pool::get_data_block_size() const
{
return md_->sb_.data_block_size_;

View File

@ -0,0 +1,199 @@
#include <iostream>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <libgen.h>
#undef BLOCK_SIZE
#include "thin-provisioning/commands.h"
#include "metadata.h"
#include "version.h"
using namespace persistent_data;
using namespace std;
using namespace thin_provisioning;
//----------------------------------------------------------------
namespace {
void confirm_pool_is_not_active() {
cout << "The pool must *not* be active when running this tool.\n"
<< "Do you wish to continue? [Y/N]\n"
<< endl;
string input;
cin >> input;
if (input != "Y")
exit(0);
}
class discard_emitter {
public:
discard_emitter(string const &data_dev, unsigned block_size, uint64_t nr_blocks)
: fd_(open_dev(data_dev, block_size * nr_blocks)),
block_size_(block_size) {
}
~discard_emitter() {
::close(fd_);
}
void emit(block_address b, block_address e) {
uint64_t range[2];
range[0] = block_to_byte(b);
range[1] = block_to_byte(e) - range[0];
if (ioctl(fd_, BLKDISCARD, &range))
throw runtime_error("discard ioctl failed");
}
private:
static int open_dev(string const &data_dev, uint64_t expected_size) {
int r, fd;
uint64_t blksize;
struct stat info;
fd = ::open(data_dev.c_str(), O_WRONLY);
if (fd < 0) {
ostringstream out;
out << "Couldn't open data device '" << data_dev << "'";
throw runtime_error(out.str());
}
try {
r = fstat(fd, &info);
if (r)
throw runtime_error("Couldn't stat data device");
if (!S_ISBLK(info.st_mode))
throw runtime_error("Data device is not a block device");
r = ioctl(fd, BLKGETSIZE64, &blksize);
if (r)
throw runtime_error("Couldn't get data device size");
if (blksize != (expected_size << 9))
throw runtime_error("Data device is not the expected size");
} catch (...) {
::close(fd);
throw;
}
return fd;
}
uint64_t block_to_byte(block_address b) {
return (b * block_size_) << 9;
}
int fd_;
unsigned block_size_;
};
class trim_visitor : public space_map_detail::visitor {
public:
trim_visitor(discard_emitter &e)
: emitter_(e) {
}
virtual void visit(space_map_detail::missing_counts const &mc) {
throw std::runtime_error("corrupt metadata, please use thin_check for details");
}
virtual void visit(block_address b, uint32_t count) {
if (last_visited_ && (b > *last_visited_ + 1))
emitter_.emit(*last_visited_ + 1, b);
last_visited_ = b;
}
private:
discard_emitter &emitter_;
boost::optional<block_address> last_visited_;
};
int trim(string const &metadata_dev, string const &data_dev) {
// We can trim any block that has zero count in the data
// space map.
metadata md(metadata_dev, 0);
if (!md.data_sm_->get_nr_free())
return 0;
discard_emitter de(data_dev, md.sb_.data_block_size_,
md.data_sm_->get_nr_blocks());
trim_visitor tv(de);
confirm_pool_is_not_active();
md.data_sm_->visit(tv);
return 0;
}
void usage(ostream &out, string const &cmd) {
out << "Usage: " << cmd << " [options] {device|file}\n"
<< "Options:\n"
<< " {--pool-inactive}\n"
<< " {-h|--help}\n"
<< " {-V|--version}" << endl;
}
struct flags {
boost::optional<string> metadata_dev;
boost::optional<string> data_dev;
};
}
//----------------------------------------------------------------
int thin_trim_main(int argc, char **argv)
{
int c;
flags fs;
const char shortopts[] = "hV";
const struct option longopts[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'V' },
{ "metadata-dev", required_argument, NULL, 0 },
{ "data-dev", required_argument, NULL, 1 },
{ "pool-inactive", no_argument, NULL, 2 },
{ NULL, no_argument, NULL, 0 }
};
while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
switch(c) {
case 0:
fs.metadata_dev = optarg;
break;
case 1:
fs.data_dev = optarg;
break;
case 'h':
usage(cout, basename(argv[0]));
return 0;
case 'V':
cout << THIN_PROVISIONING_TOOLS_VERSION << endl;
return 0;
default:
usage(cerr, basename(argv[0]));
return 1;
}
}
if (!fs.metadata_dev || !fs.data_dev) {
usage(cerr, basename(argv[0]));
return 1;
}
return trim(*fs.metadata_dev, *fs.data_dev);
}
//----------------------------------------------------------------

View File

@ -57,6 +57,7 @@ TEST_SOURCE=\
unit-tests/cache_superblock_t.cc \
unit-tests/damage_tracker_t.cc \
unit-tests/endian_t.cc \
unit-tests/error_state_t.cc \
unit-tests/rmap_visitor_t.cc \
unit-tests/run_set_t.cc \
unit-tests/space_map_t.cc \

View File

@ -35,9 +35,9 @@ using namespace testing;
namespace {
uint64_t MAX_VALUE = 1000ull;
block_address const NR_BLOCKS = 1024;
typedef typename bcache::noop_validator noop_validator;
typedef typename block_manager<>::read_ref read_ref;
typedef typename block_manager<>::write_ref write_ref;
typedef bcache::noop_validator noop_validator;
typedef block_manager<>::read_ref read_ref;
typedef block_manager<>::write_ref write_ref;
// FIXME: lift to utils?
class simple_ref_counter {

View File

@ -5,8 +5,16 @@
#include "persistent-data/data-structures/array_block.h"
#include "test_utils.h"
#include <boost/version.hpp>
#if BOOST_VERSION >= 104700
#define HAVE_RANDOM_UNIFORM_INT_DISTRIBUTION
#endif
#include <boost/random/mersenne_twister.hpp>
#ifdef HAVE_RANDOM_UNIFORM_INT_DISTRIBUTION
#include <boost/random/uniform_int_distribution.hpp>
#endif
#include <utility>
#include <deque>
#include <vector>
@ -40,10 +48,16 @@ namespace {
using namespace boost::random;
uniform_int_distribution<uint64_t> uniform_dist(0, max);
#ifdef HAVE_RANDOM_UNIFORM_INT_DISTRIBUTION
boost::random::uniform_int_distribution<uint64_t> uniform_dist(0, max);
#endif
while (r.size() < count) {
#ifdef HAVE_RANDOM_UNIFORM_INT_DISTRIBUTION
block_address b = uniform_dist(rng_);
#else
block_address b = random() % max;
#endif
r.insert(b);
}
@ -75,7 +89,9 @@ namespace {
space_map::ptr sm_;
transaction_manager tm_;
#ifdef HAVE_RANDOM_UNIFORM_INT_DISTRIBUTION
boost::random::mt19937 rng_;
#endif
};
}
@ -312,3 +328,4 @@ TEST_F(BloomFilterTests, false_positives_over_multiple_eras)
}
//----------------------------------------------------------------

View File

@ -0,0 +1,31 @@
#include "gmock/gmock.h"
#include "base/error_state.h"
using namespace base;
using namespace std;
using namespace testing;
//----------------------------------------------------------------
TEST(ErrorStateTests, stream_operator)
{
{
error_state err = NO_ERROR;
err << NO_ERROR << FATAL;
ASSERT_THAT(err, Eq(FATAL));
}
{
error_state err = NO_ERROR;
err << NO_ERROR << NON_FATAL;
ASSERT_THAT(err, Eq(NON_FATAL));
}
{
error_state err = NO_ERROR;
err << NO_ERROR << FATAL << NO_ERROR << NON_FATAL;
ASSERT_THAT(err, Eq(FATAL));
}
}
//----------------------------------------------------------------