summaryrefslogtreecommitdiffstats
path: root/src/mds/DamageTable.h
blob: a1b96fe2218642934b68e8fccdd45a6b33708188 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
 *
 * This is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1, as published by the Free Software
 * Foundation.  See file COPYING.
 *
 */


#ifndef DAMAGE_TABLE_H_
#define DAMAGE_TABLE_H_

#include <string_view>

#include "mdstypes.h"
#include "include/random.h"

class CDir;
class CInode;

typedef uint64_t damage_entry_id_t;

typedef enum
{
  DAMAGE_ENTRY_DIRFRAG,
  DAMAGE_ENTRY_DENTRY,
  DAMAGE_ENTRY_BACKTRACE

} damage_entry_type_t;

class DamageEntry
{
  public:
    DamageEntry()
    {
      id = ceph::util::generate_random_number<damage_entry_id_t>(0, 0xffffffff);
      reported_at = ceph_clock_now();
    }

    virtual ~DamageEntry();

    virtual damage_entry_type_t get_type() const = 0;
    virtual void dump(Formatter *f) const = 0;

    damage_entry_id_t id;
    utime_t reported_at;

    // path is optional, advisory.  Used to give the admin an idea of what
    // part of his tree the damage affects.
    std::string path;
};

typedef std::shared_ptr<DamageEntry> DamageEntryRef;

class DirFragIdent
{
  public:
    DirFragIdent(inodeno_t ino_, frag_t frag_)
      : ino(ino_), frag(frag_)
    {}

    bool operator<(const DirFragIdent &rhs) const
    {
      if (ino == rhs.ino) {
        return frag < rhs.frag;
      } else {
        return ino < rhs.ino;
      }
    }

    inodeno_t ino;
    frag_t frag;
};

class DentryIdent
{
  public:
    DentryIdent(std::string_view dname_, snapid_t snap_id_)
      : dname(dname_), snap_id(snap_id_)
    {}

    bool operator<(const DentryIdent &rhs) const
    {
      if (dname == rhs.dname) {
        return snap_id < rhs.snap_id;
      } else {
        return dname < rhs.dname;
      }
    }

    std::string dname;
    snapid_t snap_id;
};

/**
 * Registry of in-RADOS metadata damage identified
 * during forward scrub or during normal fetches.
 *
 * Used to indicate damage to the administrator, and
 * to cache known-bad paths so that we don't hit them
 * repeatedly.
 *
 * Callers notifying damage must check return code; if
 * an fatal condition is indicated then they should mark the MDS
 * rank damaged.
 *
 * An artificial limit on the number of damage entries
 * is imposed to avoid this structure growing indefinitely.  If
 * a notification causes the limit to be exceeded, the fatal
 * condition will be indicated in the return code and the MDS
 * rank should be marked damaged.
 *
 * Protected by MDS::mds_lock
 */
class DamageTable
{
  public:
    explicit DamageTable(const mds_rank_t rank_)
      : rank(rank_)
    {
      ceph_assert(rank_ != MDS_RANK_NONE);
    }

    /**
     * Return true if no damage entries exist
     */
    bool empty() const
    {
      return by_id.empty();
    }

    /**
     * Indicate that a dirfrag cannot be loaded.
     *
     * @return true if fatal
     */
    bool notify_dirfrag(inodeno_t ino, frag_t frag, std::string_view path);

    /**
     * Indicate that a particular dentry cannot be loaded.
     *
     * @return true if fatal
     */
    bool notify_dentry(
      inodeno_t ino, frag_t frag,
      snapid_t snap_id, std::string_view dname, std::string_view path);

    /**
     * Indicate that a particular Inode could not be loaded by number
     */
    bool notify_remote_damaged(inodeno_t ino, std::string_view path);

    void remove_dentry_damage_entry(CDir *dir);

    void remove_dirfrag_damage_entry(CDir *dir);

    void remove_backtrace_damage_entry(inodeno_t ino);

    bool is_dentry_damaged(
      const CDir *dir_frag,
      std::string_view dname,
      const snapid_t snap_id) const;

    bool is_dirfrag_damaged(const CDir *dir_frag) const;

    bool is_remote_damaged(const inodeno_t ino) const;

    void dump(Formatter *f) const;

    void erase(damage_entry_id_t damage_id);

  protected:
    // I need to know my MDS rank so that I can check if
    // metadata items are part of my mydir.
    const mds_rank_t rank;

    bool oversized() const;

    // Map of all dirfrags reported damaged
    std::map<DirFragIdent, DamageEntryRef> dirfrags;

    // Store dentries in a map per dirfrag, so that we can
    // readily look up all the bad dentries in a particular
    // dirfrag
    std::map<DirFragIdent, std::map<DentryIdent, DamageEntryRef> > dentries;

    // Map of all inodes which could not be resolved remotely
    // (i.e. have probably/possibly missing backtraces)
    std::map<inodeno_t, DamageEntryRef> remotes;

    // All damage, by ID.  This is a secondary index
    // to the dirfrag, dentry, remote maps.  It exists
    // to enable external tools to unambiguously operate
    // on particular entries.
    std::map<damage_entry_id_t, DamageEntryRef> by_id;
};
#endif // DAMAGE_TABLE_H_