Logo Search packages:      
Sourcecode: ceph version File versions  Download package

CDentry.h

// -*- 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 CEPH_CDENTRY_H
#define CEPH_CDENTRY_H

#include <string>
#include <set>
using namespace std;

#include "include/types.h"
#include "include/buffer.h"
#include "include/lru.h"
#include "include/elist.h"
#include "include/filepath.h"
#include "mdstypes.h"

#include "SimpleLock.h"
#include "LocalLock.h"

class CInode;
class CDir;
class MDRequest;

class Message;
class Anchor;

class CDentry;
class LogSegment;

class Session;



// define an ordering
bool operator<(const CDentry& l, const CDentry& r);

// dentry
class CDentry : public MDSCacheObject, public LRUObject {
private:
  static boost::pool<> pool;
public:
  static void *operator new(size_t num_bytes) { 
    void *n = pool.malloc();
    if (!n)
      throw std::bad_alloc();
    return n;
  }
  void operator delete(void *p) {
    pool.free(p);
  }

public:
  // -- state --
  static const int STATE_NEW =          (1<<0);
  static const int STATE_FRAGMENTING =  (1<<1);
  static const int STATE_PURGING =      (1<<2);
  static const int STATE_BADREMOTEINO = (1<<3);

  // -- pins --
  static const int PIN_INODEPIN =     1;  // linked inode is pinned
  static const int PIN_FRAGMENTING = -2;  // containing dir is refragmenting
  static const int PIN_PURGING =      3;
  const char *pin_name(int p) {
    switch (p) {
    case PIN_INODEPIN: return "inodepin";
    case PIN_FRAGMENTING: return "fragmenting";
    case PIN_PURGING: return "purging";
    default: return generic_pin_name(p);
    }
  };

  // -- wait --
  //static const int WAIT_LOCK_OFFSET = 8;

  void add_waiter(uint64_t tag, Context *c);

  static const int EXPORT_NONCE = 1;

  bool is_lt(const MDSCacheObject *r) const {
    return *this < *(CDentry*)r;
  }

public:
  string name;
  snapid_t first, last;

  dentry_key_t key() { 
    return dentry_key_t(last, name.c_str()); 
  }

public:
  struct linkage_t {
    CInode *inode;
    inodeno_t remote_ino;
    unsigned char remote_d_type;
    
    linkage_t() : inode(0), remote_ino(0), remote_d_type(0) {}

    // dentry type is primary || remote || null
    // inode ptr is required for primary, optional for remote, undefined for null
    bool is_primary() { return remote_ino == 0 && inode != 0; }
    bool is_remote() { return remote_ino > 0; }
    bool is_null() { return (remote_ino == 0 && inode == 0) ? true:false; }

    CInode *get_inode() { return inode; }
    inodeno_t get_remote_ino() { return remote_ino; }
    unsigned char get_remote_d_type() { return remote_d_type; }

    void set_remote(inodeno_t ino, unsigned char d_type) { 
      remote_ino = ino;
      remote_d_type = d_type;
      inode = 0;
    }
    void link_remote(CInode *in);
  };
  
protected:
  CDir *dir;     // containing dirfrag
  linkage_t linkage;
  list<linkage_t> projected;
  
  version_t version;  // dir version when last touched.
  version_t projected_version;  // what it will be when i unlock/commit.

public:
  elist<CDentry*>::item item_dirty;

protected:
  int auth_pins, nested_auth_pins;
#ifdef MDS_AUTHPIN_SET
  multiset<void*> auth_pin_set;
#endif
  int nested_anchors;

  friend class Migrator;
  friend class Locker;
  friend class MDCache;
  friend class CInode;
  friend class C_MDC_XlockRequest;


public:
  // lock
  static LockType lock_type;
  static LockType versionlock_type;

  SimpleLock lock;
  LocalLock versionlock;

 public:
  // cons
  CDentry(const string& n, 
        snapid_t f, snapid_t l) :
    name(n),
    first(f), last(l),
    dir(0),
    version(0), projected_version(0),
    item_dirty(this),
    auth_pins(0), nested_auth_pins(0), nested_anchors(0),
    lock(this, &lock_type),
    versionlock(this, &versionlock_type) {
    g_num_dn++;
    g_num_dna++;
  }
  CDentry(const string& n, inodeno_t ino, unsigned char dt,
        snapid_t f, snapid_t l) :
    name(n),
    first(f), last(l),
    dir(0),
    version(0), projected_version(0),
    item_dirty(this),
    auth_pins(0), nested_auth_pins(0), nested_anchors(0),
    lock(this, &lock_type),
    versionlock(this, &versionlock_type) {
    g_num_dn++;
    g_num_dna++;
    linkage.remote_ino = ino;
    linkage.remote_d_type = dt;
  }
  ~CDentry() {
    g_num_dn--;
    g_num_dns++;
  }


  CDir *get_dir() const { return dir; }
  const string& get_name() const { return name; }

  /*
  CInode *get_inode() const { return linkage.inode; }
  inodeno_t get_remote_ino() { return linkage.remote_ino; }
  unsigned char get_remote_d_type() { return linkage.remote_d_type; }

  // dentry type is primary || remote || null
  // inode ptr is required for primary, optional for remote, undefined for null
  bool is_primary() { return linkage.is_primary(); }
  bool is_remote() { return linkage.is_remote(); }
  bool is_null() { return linkage.is_null(); }

  inodeno_t get_ino();
  */

  linkage_t *get_linkage() { return &linkage; }

  linkage_t *_project_linkage() {
    projected.push_back(linkage_t());
    return &projected.back();
  }
  void push_projected_linkage() {
    _project_linkage();
  }
  void push_projected_linkage(inodeno_t ino, char d_type) {
    linkage_t *p = _project_linkage();
    p->remote_ino = ino;
    p->remote_d_type = d_type;
  }
  void push_projected_linkage(CInode *inode); 
  linkage_t *pop_projected_linkage();

  bool is_projected() { return projected.size(); }

  linkage_t *get_projected_linkage() {
    if (projected.size())
      return &projected.back();
    return &linkage;
  }
  CInode *get_projected_inode() {
    return get_projected_linkage()->inode;
  }

  bool use_projected(client_t client, Mutation *mut) {
    return lock.can_read_projected(client) || 
      lock.get_xlock_by() == mut;
  }
  linkage_t *get_linkage(client_t client, Mutation *mut) {
    return use_projected(client, mut) ? get_projected_linkage() : get_linkage();
  }

  // ref counts: pin ourselves in the LRU when we're pinned.
  void first_get() {
    lru_pin();
  }
  void last_put() {
    lru_unpin();
  }

  // auth pins
  bool can_auth_pin();
  void auth_pin(void *by);
  void auth_unpin(void *by);
  void adjust_nested_auth_pins(int by, int dirby);
  bool is_frozen();
  
  void adjust_nested_anchors(int by);

  // remote links
  void link_remote(linkage_t *dnl, CInode *in);
  void unlink_remote(linkage_t *dnl);
  
  // copy cons
  CDentry(const CDentry& m);
  const CDentry& operator= (const CDentry& right);

  // misc
  void make_path_string(string& s);
  void make_path(filepath& fp);
  void make_anchor_trace(vector<class Anchor>& trace, CInode *in);

  // -- version --
  version_t get_version() { return version; }
  void set_version(version_t v) { projected_version = version = v; }
  version_t get_projected_version() { return projected_version; }
  void set_projected_version(version_t v) { projected_version = v; }
  
  pair<int,int> authority();

  version_t pre_dirty(version_t min=0);
  void _mark_dirty(LogSegment *ls);
  void mark_dirty(version_t projected_dirv, LogSegment *ls);
  void mark_clean();

  void mark_new();
  bool is_new() { return state_test(STATE_NEW); }
  void clear_new() { state_clear(STATE_NEW); }
  
  // -- replication
  void encode_replica(int mds, bufferlist& bl) {
    __u32 nonce = add_replica(mds);
    ::encode(nonce, bl);
    ::encode(first, bl);
    ::encode(linkage.remote_ino, bl);
    ::encode(linkage.remote_d_type, bl);
    __s32 ls = lock.get_replica_state();
    ::encode(ls, bl);
  }
  void decode_replica(bufferlist::iterator& p, bool is_new);

  // -- exporting
  // note: this assumes the dentry already exists.  
  // i.e., the name is already extracted... so we just need the other state.
  void encode_export(bufferlist& bl) {
    ::encode(first, bl);
    ::encode(state, bl);
    ::encode(version, bl);
    ::encode(projected_version, bl);
    ::encode(lock, bl);
    ::encode(replica_map, bl);
    get(PIN_TEMPEXPORTING);
  }
  void finish_export() {
    // twiddle
    clear_replica_map();
    replica_nonce = EXPORT_NONCE;
    state_clear(CDentry::STATE_AUTH);
    if (is_dirty())
      mark_clean();
    put(PIN_TEMPEXPORTING);
  }
  void abort_export() {
    put(PIN_TEMPEXPORTING);
  }
  void decode_import(bufferlist::iterator& blp, LogSegment *ls) {
    ::decode(first, blp);
    __u32 nstate;
    ::decode(nstate, blp);
    ::decode(version, blp);
    ::decode(projected_version, blp);
    ::decode(lock, blp);
    ::decode(replica_map, blp);

    // twiddle
    state = 0;
    state_set(CDentry::STATE_AUTH);
    if (nstate & STATE_DIRTY)
      _mark_dirty(ls);
    if (!replica_map.empty())
      get(PIN_REPLICATED);
  }

  // -- locking --
  SimpleLock* get_lock(int type) {
    assert(type == CEPH_LOCK_DN);
    return &lock;
  }
  void set_object_info(MDSCacheObjectInfo &info);
  void encode_lock_state(int type, bufferlist& bl);
  void decode_lock_state(int type, bufferlist& bl);


  // ---------------------------------------------
  // replicas (on clients)
 public:
  map<client_t,ClientLease*> client_lease_map;

  bool is_any_leases() {
    return !client_lease_map.empty();
  }
  ClientLease *get_client_lease(client_t c) {
    if (client_lease_map.count(c))
      return client_lease_map[c];
    return 0;
  }
  bool have_client_lease(client_t c) {
    ClientLease *l = get_client_lease(c);
    if (l) 
      return true;
    else
      return false;
  }

  ClientLease *add_client_lease(client_t c, Session *session);
  void remove_client_lease(ClientLease *r, class Locker *locker);  // returns remaining mask (if any), and kicks locker eval_gathers
  

  
  ostream& print_db_line_prefix(ostream& out);
  void print(ostream& out);

  friend class CDir;
};

ostream& operator<<(ostream& out, CDentry& dn);


#endif

Generated by  Doxygen 1.6.0   Back to index