summaryrefslogtreecommitdiffstats
path: root/src/mds/FileLock.h
blob: c2bf5e5b0a2c96be779c691ac7d04de5b7e7c22b (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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
// -*- 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 __FILELOCK_H
#define __FILELOCK_H

#include <set>
using namespace std;

#include "include/buffer.h"

#include "SimpleLock.h"

// states and such.
//  C = cache reads, R = read, W = write, A = append, B = buffer writes, L = lazyio

//                               -----auth--------   ---replica-------
#define LOCK_SYNC_    1  // AR   R . / C R . . . L   R . / C R . . . L   stat()
#define LOCK_GSYNCL  -12 // A    . . / C ? . . . L                       loner -> sync (*)
#define LOCK_GSYNCM  -13 // A    . . / . R . . . L

#define LOCK_LOCK_    2  // AR   R W / C . . . B .   . . / C . . . . .   truncate()
#define LOCK_GLOCKR_ -3  // AR   R . / C . . . . .   . . / C . . . . .
#define LOCK_GLOCKL  -4  // A    . . / C . . . B .                       loner -> lock
#define LOCK_GLOCKM  -5  // A    . . / . . . . . .

#define LOCK_MIXED    6  // AR   . . / . R W A . L   . . / . R . . . L
#define LOCK_GMIXEDR -7  // AR   R . / . R . . . L   . . / . R . . . L 
#define LOCK_GMIXEDL -8  // A    . . / . . . . . L                       loner -> mixed

#define LOCK_LONER    9  // A    . . / C R W A B L        (lock)      
#define LOCK_GLONERR -10 // A    . . / . R . . . L
#define LOCK_GLONERM -11 // A    . . / . R W A . L

// (*) FIXME: how to let old loner keep R, somehow, during GSYNCL

//   4 stable
//  +9 transition
//  13 total

inline const char *get_filelock_state_name(int n) {
  switch (n) {
  case LOCK_SYNC: return "sync";
  case LOCK_GSYNCL: return "gsyncl";
  case LOCK_GSYNCM: return "gsyncm";
  case LOCK_LOCK: return "lock";
  case LOCK_GLOCKR: return "glockr";
  case LOCK_GLOCKL: return "glockl";
  case LOCK_GLOCKM: return "glockm";
  case LOCK_MIXED: return "mixed";
  case LOCK_GMIXEDR: return "gmixedr";
  case LOCK_GMIXEDL: return "gmixedl";
  case LOCK_LONER: return "loner";
  case LOCK_GLONERR: return "glonerr";
  case LOCK_GLONERM: return "glonerm";
  default: assert(0); return 0;
  }
}


/* no append scenarios:

loner + truncate():
  - loner needs to lose A (?unless it's the loner doing the truncate?)
loner + statlite(size):
  - loner needs to lose A

any + statlite(size)
  - all lose A

any + statlite(mtime)
  - all lose W

-> we need to add lonerfixed and mixedfixed states (and associated transitions)
 in order to efficiently support statlite(size) and truncate().  until then,
 we have to LOCK.

 */

// -- lock... hard or file

class Mutation;

class FileLock : public SimpleLock {
  int num_wrlock;

 public:
  FileLock(MDSCacheObject *o, int t, int wo) : 
    SimpleLock(o, t, wo),
    num_wrlock(0) { }
  
  int get_replica_state() const {
    switch (state) {
    case LOCK_LOCK:
    case LOCK_GLOCKM:
    case LOCK_GLOCKL:
    case LOCK_GLOCKR: 
    case LOCK_LONER:
    case LOCK_GLONERR:
    case LOCK_GLONERM:
      return LOCK_LOCK;
    case LOCK_MIXED:
    case LOCK_GMIXEDR:
      return LOCK_MIXED;
    case LOCK_SYNC:
      return LOCK_SYNC;

      // after gather auth will bc LOCK_AC_MIXED or whatever
    case LOCK_GSYNCM:
      return LOCK_MIXED;
    case LOCK_GSYNCL:
    case LOCK_GMIXEDL:     // ** LOCK isn't exact right state, but works.
      return LOCK_LOCK;

    default: 
      assert(0);
    }
    return 0;
  }
  void export_twiddle() {
    clear_gather();
    state = get_replica_state();
  }

  // read/write access
  bool can_rdlock(Mutation *mdr) {
    if (!parent->is_auth()) return (state == LOCK_SYNC);
    //if (state == LOCK_LOCK && mdr && xlock_by == mdr) return true;
    if (state == LOCK_LOCK && !xlock_by) return true;
    return 
      (state == LOCK_SYNC) ||
      (state == LOCK_GMIXEDR) || 
      (state == LOCK_GLOCKR);
  }
  bool can_rdlock_soon() {
    if (parent->is_auth())
      return
	(state == LOCK_GLOCKL) ||
	(state == LOCK_LOCK && xlock_by);
    else
      return false;
  }
  bool can_xlock_soon() {
    if (parent->is_auth())
      return (state == LOCK_GLOCKR) || (state == LOCK_GLOCKL)
        || (state == LOCK_GLOCKM);
    else
      return false;
  }

  // wrlock
  bool can_wrlock() {
    return 
      parent->is_auth() && 
      (state == LOCK_LOCK || state == LOCK_GLOCKM || state == LOCK_GLOCKL ||
       state == LOCK_MIXED || state == LOCK_GMIXEDL ||
       state == LOCK_LONER || state == LOCK_GLONERM ||
       state == LOCK_GSYNCM || state == LOCK_GSYNCL);
  }
  void get_wrlock(bool force) {
    assert(force || can_wrlock());
    if (num_wrlock == 0) parent->get(MDSCacheObject::PIN_LOCK);
    ++num_wrlock;
  }
  void put_wrlock() {
    --num_wrlock;
    if (num_wrlock == 0) parent->put(MDSCacheObject::PIN_LOCK);
  }
  bool is_wrlocked() { return num_wrlock > 0; }
  int get_num_wrlocks() { return num_wrlock; }


  // client caps allowed
  int caps_allowed_ever() {
    if (parent->is_auth())
      return CEPH_CAP_PIN | 
	CEPH_CAP_RDCACHE | CEPH_CAP_RD | 
	CEPH_CAP_WR | CEPH_CAP_WREXTEND | CEPH_CAP_WRBUFFER | CEPH_CAP_EXCL |
	CEPH_CAP_LAZYIO;
    else
      return CEPH_CAP_PIN | 
	CEPH_CAP_RDCACHE | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
  }
  int caps_allowed() {
    if (parent->is_auth())
      switch (state) {
      case LOCK_SYNC:
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      case LOCK_GLOCKR:
         return CEPH_CAP_PIN | CEPH_CAP_RDCACHE;
      case LOCK_LOCK:
      case LOCK_GLOCKL:
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE | CEPH_CAP_WRBUFFER;

      case LOCK_GLOCKM:
        return CEPH_CAP_PIN;

      case LOCK_MIXED:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_WR | CEPH_CAP_WREXTEND | CEPH_CAP_LAZYIO;
      case LOCK_GMIXEDR:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      case LOCK_GMIXEDL:
        return CEPH_CAP_PIN;

      case LOCK_LONER:  // single client writer, of course.
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE | CEPH_CAP_RD | CEPH_CAP_WR | CEPH_CAP_WREXTEND | CEPH_CAP_WRBUFFER | CEPH_CAP_LAZYIO | CEPH_CAP_EXCL;
      case LOCK_GLONERR:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      case LOCK_GLONERM:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_WR | CEPH_CAP_WREXTEND | CEPH_CAP_LAZYIO;

      case LOCK_GSYNCL:
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE | CEPH_CAP_LAZYIO;
      case LOCK_GSYNCM:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      }
    else
      switch (state) {
      case LOCK_SYNC:
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      case LOCK_LOCK:
      case LOCK_GLOCKR:
        return CEPH_CAP_PIN | CEPH_CAP_RDCACHE;
      case LOCK_GMIXEDR:
      case LOCK_MIXED:
        return CEPH_CAP_PIN | CEPH_CAP_RD | CEPH_CAP_LAZYIO;
      }
    assert(0);
    return 0;
  }

  void print(ostream& out) {
    out << "(";
    out << get_lock_type_name(get_type()) << " ";
    out << get_filelock_state_name(get_state());
    if (!get_gather_set().empty()) out << " g=" << get_gather_set();
    if (get_num_client_lease())
      out << " c=" << get_num_client_lease();
    if (is_wrlocked())
      out << " w=" << get_num_wrlocks();
    if (is_rdlocked()) 
      out << " r=" << get_num_rdlocks();
    if (is_xlocked())
      out << " x=" << get_xlocked_by();
    out << ")";
  }
};


#endif