1package MogileFS::ReplicationRequest;
2use strict;
3use MogileFS::Server;
4require Exporter;
5our @ISA = qw(Exporter);
6our @EXPORT_OK = qw(rr_upgrade ALL_GOOD TOO_GOOD TEMP_NO_ANSWER);
7
8my $no_answer = bless { temp_fail => 1 };
9sub TEMP_NO_ANSWER () { $no_answer }
10my $all_good = bless { all_good => 1 };
11sub ALL_GOOD () { $all_good }
12my $too_good = bless { all_good => 1, too_good => 1 };
13sub TOO_GOOD () { $too_good }
14
15# upgrades the return values from old-style ReplicationPolicy classes
16# to MogileFS::ReplicationRequest objects, unless they already are,
17# in which case they're passed through unchanged.  provides peaceful
18# upgrade path for old plugins.
19sub rr_upgrade {
20    my ($rv) = @_;
21    return $rv            if ref $rv;
22    return TEMP_NO_ANSWER if !defined $rv;
23    return ALL_GOOD       if !$rv;
24    return MogileFS::ReplicationRequest->replicate_to($rv);
25}
26
27# for ideal replications
28sub replicate_to {
29    my ($class, @devs) = @_;
30    @devs = map { ref $_ ? $_ : Mgd::device_factory()->get_by_id($_) } @devs;
31    return bless {
32        ideal_next => \@devs,
33    }, $class;
34}
35
36sub new {
37    my ($class, %opts) = @_;
38    my $self = bless {}, $class;
39    $self->{ideal_next}     = delete $opts{ideal}     || [];
40    $self->{desperate_next} = delete $opts{desperate} || [];
41    Carp::croak("unknown args") if %opts;
42    return $self;
43}
44
45############################################################################
46
47sub is_happy {
48    my $self = shift;
49    return $self->{all_good};
50}
51
52sub too_happy {
53    my $self = shift;
54    return $self->{too_good};
55}
56
57sub temp_fail {
58    my $self = shift;
59    return $self->{temp_fail};
60}
61
62# returns array of MogileFS::Device objs, in preferred order, one of
63# which (but not multiple) would satisfy the replication policy
64# for its next step.  at which point the replication policy needs
65# to be asked again what the next step is.
66sub copy_to_one_of_ideally {
67    my $self = shift;
68    return @{ $self->{ideal_next} || [] };
69}
70
71# like above, but replication policy isn't happy about these choices,
72# so a reevaluation of this replication decision should be made in the
73# future, when new disks/hosts might be available.
74sub copy_to_one_of_desperate {
75    my $self = shift;
76    return @{ $self->{desperate_next} || [] };
77}
78
79# for test suite..
80sub t_as_string {
81    my $self = shift;
82    return "too_good"  if $self->{too_good};
83    return "all_good"  if $self->{all_good};
84    return "temp_fail" if $self->{temp_fail};
85    my @devs;
86    if (@devs = $self->copy_to_one_of_ideally) {
87        return "ideal(" . join(",", sort {$a<=>$b} map { $_->id } @devs) . ")";
88    }
89    if (@devs = $self->copy_to_one_of_desperate) {
90        return "desperate(" . join(",", sort {$a<=>$b}  map { $_->id } @devs) . ")";
91    }
92    die "unknown $self type";
93}
94
951;
96
97