summaryrefslogtreecommitdiffstats
path: root/src/mds/StrayManager.h
blob: 874fbbb9a8dcd449375780ac5bbc4d2fddf7a3b4 (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
204
205
206
207
208
209
210
211
212
213
// vim: ts=8 sw=2 smarttab
/*
 * Ceph - scalable distributed file system
 *
 * Copyright (C) 2015 Red Hat
 *
 * 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 STRAY_MANAGER_H
#define STRAY_MANAGER_H

#include "include/common_fwd.h"
#include "include/elist.h"
#include <list>
#include "Mutation.h"
#include "PurgeQueue.h"
#include "MDSMetaRequest.h"
#include "CDentry.h"

class MDSRank;
class CInode;

class StrayManager
{
  // My public interface is for consumption by MDCache
public:
  struct StrayEvalRequest : public MDSMetaRequest {
    CDentry *dentry;
  public:
    explicit StrayEvalRequest(int o, ceph_tid_t t, CDentry *d) :
      MDSMetaRequest(o, t), dentry(d) {
      dentry->get(CDentry::PIN_PURGING);
      dentry->reintegration_reqid = t;
    }
    ~StrayEvalRequest() {
      dentry->reintegration_reqid = 0;
      dentry->put(CDentry::PIN_PURGING);
    }
  };

  explicit StrayManager(MDSRank *mds, PurgeQueue &purge_queue_);
  void set_logger(PerfCounters *l) {logger = l;}
  void activate();

  bool eval_stray(CDentry *dn);

  void set_num_strays(uint64_t num);
  uint64_t get_num_strays() const { return num_strays; }

  /**
   * Queue dentry for later evaluation. (evaluate it while not in the
   * middle of another metadata operation)
   */
  void queue_delayed(CDentry *dn);

  /**
   * Eval strays in the delayed_eval_stray list
   */
  void advance_delayed();

  /**
   * Remote dentry potentially points to a stray. When it is touched,
   * call in here to evaluate it for migration (move a stray residing
   * on another MDS to this MDS) or reintegration (move a stray dentry's
   * inode into a non-stray hardlink dentry and clean up the stray).
   *
   * @param stray_dn a stray dentry whose inode has been referenced
   *                 by a remote dentry
   * @param remote_dn (optional) which remote dentry was touched
   *                  in an operation that led us here: this is used
   *                  as a hint for which remote to reintegrate into
   *                  if there are multiple remotes.
   */
  void eval_remote(CDentry *remote_dn);

  /**
   * Given a dentry within one of my stray directories,
   * send it off to a stray directory in another MDS.
   *
   * This is for use:
   *  * Case A: when shutting down a rank, we migrate strays
   *    away from ourselves rather than waiting for purge
   *  * Case B: when a client request has a trace that refers to
   *    a stray inode on another MDS, we migrate that inode from
   *    there to here, in order that we can later re-integrate it
   *    here.
   *
   * In case B, the receiver should be calling into eval_stray
   * on completion of mv (i.e. inode put), resulting in a subsequent
   * reintegration.
   */
  void migrate_stray(CDentry *dn, mds_rank_t dest);

  /**
   * Update stats to reflect a newly created stray dentry. Needed
   * because stats on strays live here, but creation happens
   * in Server or MDCache. For our purposes "creation" includes
   * loading a stray from a dirfrag and migrating a stray from
   * another MDS, in addition to creations per-se.
   */
  void notify_stray_created();

  /**
   * Update stats to reflect a removed stray dentry. Needed because
   * stats on strays live here, but removal happens in Server or
   * MDCache. Also includes migration (rename) of strays from
   * this MDS to another MDS.
   */
  void notify_stray_removed();

protected:
  friend class StrayManagerIOContext;
  friend class StrayManagerLogContext;
  friend class StrayManagerContext;

  friend class C_StraysFetched;
  friend class C_RetryEnqueue;
  friend class C_PurgeStrayLogged;
  friend class C_TruncateStrayLogged;
  friend class C_IO_PurgeStrayPurged;

  void truncate(CDentry *dn);

  /**
   * Purge a dentry from a stray directory. This function
   * is called once eval_stray is satisfied and StrayManager
   * throttling is also satisfied. There is no going back
   * at this stage!
   */
  void purge(CDentry *dn);

  /**
   * Completion handler for a Filer::purge on a stray inode.
   */
  void _purge_stray_purged(CDentry *dn, bool only_head);

  void _purge_stray_logged(CDentry *dn, version_t pdv, MutationRef& mut);

  /**
   * Callback: we have logged the update to an inode's metadata
   * reflecting it's newly-zeroed length.
   */
  void _truncate_stray_logged(CDentry *dn, MutationRef &mut);
  /**
   * Call this on a dentry that has been identified as
   * eligible for purging. It will be passed on to PurgeQueue.
   */
  void enqueue(CDentry *dn, bool trunc);
  /**
   * Final part of enqueue() which we may have to retry
   * after opening snap parents.
   */
  void _enqueue(CDentry *dn, bool trunc);

  /**
   * When hard links exist to an inode whose primary dentry
   * is unlinked, the inode gets a stray primary dentry.
   *
   * We may later "reintegrate" the inode into a remaining
   * non-stray dentry (one of what was previously a remote
   * dentry) by issuing a rename from the stray to the other
   * dentry.
   */
  void reintegrate_stray(CDentry *dn, CDentry *rlink);

  /**
   * Evaluate a stray dentry for purging or reintegration.
   *
   * purging: If the inode has no linkage, and no more references, then
   *          we may decide to purge it.
   *
   * reintegration: If the inode still has linkage, then it means someone else
   *                (a hard link) is still referring to it, and we should
   *                think about reintegrating that inode into the remote dentry.
   *
   * @returns true if the dentry will be purged (caller should never
   *          take more refs after this happens), else false.
   */
  bool _eval_stray(CDentry *dn);

  void _eval_stray_remote(CDentry *stray_dn, CDentry *remote_dn);

  // Has passed through eval_stray and still has refs
  elist<CDentry*> delayed_eval_stray;

  // strays that have been trimmed from cache
  std::set<std::string> trimmed_strays;

  // Global references for doing I/O
  MDSRank *mds;
  PerfCounters *logger = nullptr;

  bool started = false;

  // Stray dentries for this rank (including those not in cache)
  uint64_t num_strays = 0;

  // Stray dentries
  uint64_t num_strays_delayed = 0;
  /**
   * Entries that have entered enqueue() but not been persistently
   * recorded by PurgeQueue yet
   */
  uint64_t num_strays_enqueuing = 0;

  PurgeQueue &purge_queue;
};
#endif  // STRAY_MANAGER_H