Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

luminous: osd: Include dups in copy_after() and copy_up_to() #28185

Merged
merged 7 commits into from Jun 20, 2019
136 changes: 136 additions & 0 deletions qa/standalone/osd/osd-backfill-recovery-log.sh
@@ -0,0 +1,136 @@
#!/usr/bin/env bash
#
# Copyright (C) 2019 Red Hat <contact@redhat.com>
#
# Author: David Zafman <dzafman@redhat.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU Library Public License as published by
# the Free Software Foundation; either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Library Public License for more details.
#

source $CEPH_ROOT/qa/standalone/ceph-helpers.sh

function run() {
local dir=$1
shift

# Fix port????
export CEPH_MON="127.0.0.1:7129" # git grep '\<7129\>' : there must be only one
export CEPH_ARGS
CEPH_ARGS+="--fsid=$(uuidgen) --auth-supported=none "
CEPH_ARGS+="--mon-host=$CEPH_MON --osd_max_backfills=1 --debug_reserver=20 "

local funcs=${@:-$(set | sed -n -e 's/^\(TEST_[0-9a-z_]*\) .*/\1/p')}
for func in $funcs ; do
setup $dir || return 1
$func $dir || return 1
teardown $dir || return 1
done
}


function _common_test() {
local dir=$1
local extra_opts="$2"
local loglen="$3"
local dupslen="$4"
local objects="$5"
local moreobjects=${6:-0}

local OSDS=6

run_mon $dir a || return 1
run_mgr $dir x || return 1
export CEPH_ARGS
export EXTRA_OPTS=" $extra_opts"

for osd in $(seq 0 $(expr $OSDS - 1))
do
run_osd $dir $osd || return 1
done

create_pool test 1 1

for j in $(seq 1 $objects)
do
rados -p test put obj-${j} /etc/passwd
done

# Mark out all OSDs for this pool
ceph osd out $(ceph pg dump pgs --format=json | jq '.pg_stats[0].up[]')
if [ "$moreobjects" != "0" ]; then
for j in $(seq 1 $moreobjects)
do
rados -p test put obj-more-${j} /etc/passwd
done
fi
sleep 1
wait_for_clean

newprimary=$(ceph pg dump pgs --format=json | jq '.pg_stats[0].up_primary')
kill_daemons

ERRORS=0
_objectstore_tool_nodown $dir $newprimary --no-mon-config --pgid 1.0 --op log | tee $dir/result.log
LOGLEN=$(jq '.pg_log_t.log | length' $dir/result.log)
if [ $LOGLEN != "$loglen" ]; then
echo "FAILED: Wrong log length got $LOGLEN (expected $loglen)"
ERRORS=$(expr $ERRORS + 1)
fi
DUPSLEN=$(jq '.pg_log_t.dups | length' $dir/result.log)
if [ $DUPSLEN != "$dupslen" ]; then
echo "FAILED: Wrong dups length got $DUPSLEN (expected $dupslen)"
ERRORS=$(expr $ERRORS + 1)
fi
grep "copy_up_to\|copy_after" $dir/osd.*.log
rm -f $dir/result.log
if [ $ERRORS != "0" ]; then
echo TEST FAILED
return 1
fi
}


# Cause copy_up_to() to only partially copy logs, copy additional dups, and trim dups
function TEST_backfill_log_1() {
local dir=$1

_common_test $dir "--osd_min_pg_log_entries=1 --osd_max_pg_log_entries=2 --osd_pg_log_dups_tracked=10" 1 9 150
}


# Cause copy_up_to() to only partially copy logs, copy additional dups
function TEST_backfill_log_2() {
local dir=$1

_common_test $dir "--osd_min_pg_log_entries=1 --osd_max_pg_log_entries=2" 1 149 150
}


# Cause copy_after() to only copy logs, no dups
function TEST_recovery_1() {
local dir=$1

_common_test $dir "--osd_min_pg_log_entries=50 --osd_max_pg_log_entries=50 --osd_pg_log_dups_tracked=60 --osd_pg_log_trim_min=10" 40 0 40
}


# Cause copy_after() to copy logs with dups
function TEST_recovery_2() {
local dir=$1

_common_test $dir "--osd_min_pg_log_entries=150 --osd_max_pg_log_entries=150 --osd_pg_log_dups_tracked=3000 --osd_pg_log_trim_min=10" 151 10 141 20
}

main osd-backfill-recovery-log "$@"

# Local Variables:
# compile-command: "make -j4 && ../qa/run-standalone.sh osd-backfill-recovery-log.sh"
# End:
6 changes: 3 additions & 3 deletions src/osd/PG.cc
Expand Up @@ -1792,7 +1792,7 @@ void PG::activate(ObjectStore::Transaction& t,
get_osdmap()->get_epoch(), pi);

// send some recent log, so that op dup detection works well.
m->log.copy_up_to(pg_log.get_log(), cct->_conf->osd_min_pg_log_entries);
m->log.copy_up_to(cct, pg_log.get_log(), cct->_conf->osd_min_pg_log_entries);
m->info.log_tail = m->log.tail;
pi.log_tail = m->log.tail; // sigh...

Expand All @@ -1804,7 +1804,7 @@ void PG::activate(ObjectStore::Transaction& t,
i->shard, pg_whoami.shard,
get_osdmap()->get_epoch(), info);
// send new stuff to append to replicas log
m->log.copy_after(pg_log.get_log(), pi.last_update);
m->log.copy_after(cct, pg_log.get_log(), pi.last_update);
}

// share past_intervals if we are creating the pg on the replica
Expand Down Expand Up @@ -5666,7 +5666,7 @@ void PG::fulfill_log(
<< ", sending full log instead";
mlog->log = pg_log.get_log(); // primary should not have requested this!!
} else
mlog->log.copy_after(pg_log.get_log(), query.since);
mlog->log.copy_after(cct, pg_log.get_log(), query.since);
}
else if (query.type == pg_query_t::FULLLOG) {
dout(10) << " sending info+missing+full log" << dendl;
Expand Down
10 changes: 5 additions & 5 deletions src/osd/PGLog.cc
Expand Up @@ -57,8 +57,9 @@ void PGLog::IndexedLog::trim(
auto earliest_dup_version =
log.rbegin()->version.version < cct->_conf->osd_pg_log_dups_tracked
? 0u
: log.rbegin()->version.version - cct->_conf->osd_pg_log_dups_tracked;
: log.rbegin()->version.version - cct->_conf->osd_pg_log_dups_tracked + 1;

lgeneric_subdout(cct, osd, 20) << "earliest_dup_version = " << earliest_dup_version << dendl;
while (!log.empty()) {
const pg_log_entry_t &e = *log.begin();
if (e.version > s)
Expand All @@ -70,7 +71,6 @@ void PGLog::IndexedLog::trim(
unindex(e); // remove from index,

// add to dup list
lgeneric_subdout(cct, osd, 20) << "earliest_dup_version = " << earliest_dup_version << dendl;
if (e.version.version >= earliest_dup_version) {
if (write_from_dups != nullptr && *write_from_dups > e.version) {
lgeneric_subdout(cct, osd, 20) << "updating write_from_dups from " << *write_from_dups << " to " << e.version << dendl;
Expand Down Expand Up @@ -543,12 +543,12 @@ bool PGLog::merge_log_dups(const pg_log_t& olog) {
}

// remove any dup entries that overlap with pglog
if (!log.dups.empty() && log.dups.back().version >= log.tail) {
dout(10) << "merge_log removed dups overlapping log entries [" <<
if (!log.dups.empty() && log.dups.back().version > log.tail) {
dout(10) << "merge_log removed dups overlapping log entries (" <<
log.tail << "," << log.dups.back().version << "]" << dendl;
changed = true;

while (!log.dups.empty() && log.dups.back().version >= log.tail) {
while (!log.dups.empty() && log.dups.back().version > log.tail) {
log.unindex(log.dups.back());
mark_dirty_from_dups(log.dups.back().version);
log.dups.pop_back();
Expand Down
60 changes: 38 additions & 22 deletions src/osd/osd_types.cc
Expand Up @@ -4339,11 +4339,41 @@ void pg_log_t::generate_test_instances(list<pg_log_t*>& o)
o.back()->log.push_back(**p);
}

void pg_log_t::copy_after(const pg_log_t &other, eversion_t v)
static void _handle_dups(CephContext* cct, pg_log_t &target, const pg_log_t &other, unsigned maxdups)
{
auto earliest_dup_version =
target.head.version < maxdups ? 0u : target.head.version - maxdups + 1;
lgeneric_subdout(cct, osd, 20) << "copy_up_to/copy_after earliest_dup_version " << earliest_dup_version << dendl;

for (auto d = other.dups.cbegin(); d != other.dups.cend(); ++d) {
if (d->version.version >= earliest_dup_version) {
lgeneric_subdout(cct, osd, 20)
<< "copy_up_to/copy_after copy dup version "
<< d->version << dendl;
target.dups.push_back(pg_log_dup_t(*d));
}
}

for (auto i = other.log.cbegin(); i != other.log.cend(); ++i) {
ceph_assert(i->version > other.tail);
if (i->version > target.tail)
break;
if (i->version.version >= earliest_dup_version) {
lgeneric_subdout(cct, osd, 20)
<< "copy_up_to/copy_after copy dup from log version "
<< i->version << dendl;
target.dups.push_back(pg_log_dup_t(*i));
}
}
}


void pg_log_t::copy_after(CephContext* cct, const pg_log_t &other, eversion_t v)
{
can_rollback_to = other.can_rollback_to;
head = other.head;
tail = other.tail;
lgeneric_subdout(cct, osd, 20) << __func__ << " v " << v << dendl;
for (list<pg_log_entry_t>::const_reverse_iterator i = other.log.rbegin();
i != other.log.rend();
++i) {
Expand All @@ -4353,45 +4383,31 @@ void pg_log_t::copy_after(const pg_log_t &other, eversion_t v)
tail = i->version;
break;
}
lgeneric_subdout(cct, osd, 20) << __func__ << " copy log version " << i->version << dendl;
log.push_front(*i);
}
_handle_dups(cct, *this, other, cct->_conf->osd_pg_log_dups_tracked);
}

void pg_log_t::copy_range(const pg_log_t &other, eversion_t from, eversion_t to)
{
can_rollback_to = other.can_rollback_to;
list<pg_log_entry_t>::const_reverse_iterator i = other.log.rbegin();
assert(i != other.log.rend());
while (i->version > to) {
++i;
assert(i != other.log.rend());
}
assert(i->version == to);
head = to;
for ( ; i != other.log.rend(); ++i) {
if (i->version <= from) {
tail = i->version;
break;
}
log.push_front(*i);
}
}

void pg_log_t::copy_up_to(const pg_log_t &other, int max)
void pg_log_t::copy_up_to(CephContext* cct, const pg_log_t &other, int max)
{
can_rollback_to = other.can_rollback_to;
int n = 0;
head = other.head;
tail = other.tail;
lgeneric_subdout(cct, osd, 20) << __func__ << " max " << max << dendl;
for (list<pg_log_entry_t>::const_reverse_iterator i = other.log.rbegin();
i != other.log.rend();
++i) {
ceph_assert(i->version > other.tail);
if (n++ >= max) {
tail = i->version;
break;
}
lgeneric_subdout(cct, osd, 20) << __func__ << " copy log version " << i->version << dendl;
log.push_front(*i);
}
_handle_dups(cct, *this, other, cct->_conf->osd_pg_log_dups_tracked);
}

ostream& pg_log_t::print(ostream& out) const
Expand Down
13 changes: 2 additions & 11 deletions src/osd/osd_types.h
Expand Up @@ -3666,24 +3666,15 @@ struct pg_log_t {
* @param other pg_log_t to copy from
* @param from copy entries after this version
*/
void copy_after(const pg_log_t &other, eversion_t from);

/**
* copy a range of entries from another pg_log_t
*
* @param other pg_log_t to copy from
* @param from copy entries after this version
* @param to up to and including this version
*/
void copy_range(const pg_log_t &other, eversion_t from, eversion_t to);
void copy_after(CephContext* cct, const pg_log_t &other, eversion_t from);

/**
* copy up to N entries
*
* @param other source log
* @param max max number of entries to copy
*/
void copy_up_to(const pg_log_t &other, int max);
void copy_up_to(CephContext* cct, const pg_log_t &other, int max);

ostream& print(ostream& out) const;

Expand Down