]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
merged r1961:1988 from ceph/branches/sage/crush back into trunk
authorsageweil <sageweil@29311d96-e01e-0410-9327-a35deaab8ce9>
Tue, 23 Oct 2007 21:53:24 +0000 (21:53 +0000)
committersageweil <sageweil@29311d96-e01e-0410-9327-a35deaab8ce9>
Tue, 23 Oct 2007 21:53:24 +0000 (21:53 +0000)
git-svn-id: https://ceph.svn.sf.net/svnroot/ceph@1989 29311d96-e01e-0410-9327-a35deaab8ce9

75 files changed:
trunk/ceph/Makefile
trunk/ceph/crush.old/BinaryTree.h [new file with mode: 0644]
trunk/ceph/crush.old/Bucket.h [new file with mode: 0644]
trunk/ceph/crush.old/Hash.h [new file with mode: 0644]
trunk/ceph/crush.old/crush.h [new file with mode: 0644]
trunk/ceph/crush.old/test/bucket_movement.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/bucket_variance.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/cluster_movement.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/cluster_movement_remove.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/cluster_movement_rush.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/creeping_failure.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/creeping_failure_variance.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/depth_variance.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/mixed.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/movement.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/movement_failed.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/overload.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/overload_variance.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/sizes.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/smallbucket.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/speed_bucket.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/speed_depth.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/speed_rush.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/t.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/testbucket.cc [new file with mode: 0644]
trunk/ceph/crush.old/test/testnormal.cc [new file with mode: 0644]
trunk/ceph/crush/BinaryTree.h [deleted file]
trunk/ceph/crush/Bucket.h [deleted file]
trunk/ceph/crush/CrushWrapper.h [new file with mode: 0644]
trunk/ceph/crush/Hash.h [deleted file]
trunk/ceph/crush/Makefile [new file with mode: 0644]
trunk/ceph/crush/buckets.c [new file with mode: 0644]
trunk/ceph/crush/builder.c [new file with mode: 0644]
trunk/ceph/crush/builder.h [new file with mode: 0644]
trunk/ceph/crush/crush.c [new file with mode: 0644]
trunk/ceph/crush/crush.h
trunk/ceph/crush/hash.h [new file with mode: 0644]
trunk/ceph/crush/mapper.c [new file with mode: 0644]
trunk/ceph/crush/mapper.h [new file with mode: 0644]
trunk/ceph/crush/test.c [new file with mode: 0644]
trunk/ceph/crush/test/bucket_movement.cc [deleted file]
trunk/ceph/crush/test/bucket_variance.cc [deleted file]
trunk/ceph/crush/test/cluster_movement.cc [deleted file]
trunk/ceph/crush/test/cluster_movement_remove.cc [deleted file]
trunk/ceph/crush/test/cluster_movement_rush.cc [deleted file]
trunk/ceph/crush/test/creeping_failure.cc [deleted file]
trunk/ceph/crush/test/creeping_failure_variance.cc [deleted file]
trunk/ceph/crush/test/depth_variance.cc [deleted file]
trunk/ceph/crush/test/mixed.cc [deleted file]
trunk/ceph/crush/test/movement.cc [deleted file]
trunk/ceph/crush/test/movement_failed.cc [deleted file]
trunk/ceph/crush/test/overload.cc [deleted file]
trunk/ceph/crush/test/overload_variance.cc [deleted file]
trunk/ceph/crush/test/sizes.cc [deleted file]
trunk/ceph/crush/test/smallbucket.cc [deleted file]
trunk/ceph/crush/test/speed_bucket.cc [deleted file]
trunk/ceph/crush/test/speed_depth.cc [deleted file]
trunk/ceph/crush/test/speed_rush.cc [deleted file]
trunk/ceph/crush/test/t.cc [deleted file]
trunk/ceph/crush/test/testbucket.cc [deleted file]
trunk/ceph/crush/test/testnormal.cc [deleted file]
trunk/ceph/crush/types.h [new file with mode: 0644]
trunk/ceph/crush2/Makefile [deleted file]
trunk/ceph/crush2/buckets.c [deleted file]
trunk/ceph/crush2/buckets.h [deleted file]
trunk/ceph/crush2/builder.c [deleted file]
trunk/ceph/crush2/crush.c [deleted file]
trunk/ceph/crush2/crush.h [deleted file]
trunk/ceph/crush2/hash.h [deleted file]
trunk/ceph/crush2/types.h [deleted file]
trunk/ceph/mon/OSDMonitor.cc
trunk/ceph/mon/OSDMonitor.h
trunk/ceph/osd/OSDMap.h
trunk/ceph/osd/PG.h
trunk/ceph/osd/osd_types.h

index f1dc7b3d4d60a7ac7d45301d03e8efe4a6be4859..52fc13494c3c665a376b81c69d8e6aab076440a0 100644 (file)
@@ -16,7 +16,7 @@
 EXTRA_CFLAGS = #-I${HOME}/include -L${HOME}/lib
 EXTRA_CFLAGS += -g
 EXTRA_CFLAGS += -pg
-EXTRA_CFLAGS += -O3
+#EXTRA_CFLAGS += -O3
 
 # base
 CFLAGS = -Wall -I. -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D_THREAD_SAFE ${EXTRA_CFLAGS}
@@ -145,22 +145,22 @@ mkmonmap: mkmonmap.cc common.o
 extractosdmaps: extractosdmaps.cc common.o osd.o mon.o ebofs.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
-cmon: cmon.o mon.o msg/SimpleMessenger.o common.o
+cmon: cmon.o mon.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
 cmonctl: cmonctl.cc msg/SimpleMessenger.o common.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
-cosd: cosd.o osd.o ebofs.o msg/SimpleMessenger.o common.o
+cosd: cosd.o osd.o ebofs.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
-cmds: cmds.o mds.o osdc.o msg/SimpleMessenger.o common.o
+cmds: cmds.o mds.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
-csyn: csyn.o client.o osdc.o msg/SimpleMessenger.o common.o
+csyn: csyn.o client.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
-cfuse: cfuse.o client.o osdc.o client/fuse.o client/fuse_ll.o msg/SimpleMessenger.o common.o
+cfuse: cfuse.o client.o osdc.o client/fuse.o client/fuse_ll.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} -lfuse $^ -o $@
 
 
@@ -191,15 +191,15 @@ ipc_testclient: ceph_ipc/ipc_testclient.cc ceph_ipc/ipc_client.o
 
 
 # fake*
-fakefuse: fakefuse.o mon.o mds.o client.o osd.o osdc.o ebofs.o client/fuse.o client/fuse_ll.o msg/FakeMessenger.o common.o
+fakefuse: fakefuse.o mon.o mds.o client.o osd.o osdc.o ebofs.o client/fuse.o client/fuse_ll.o msg/FakeMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} -lfuse $^ -o $@
 
-fakesyn: fakesyn.o mon.o mds.o client.o osd.o ebofs.o osdc.o msg/FakeMessenger.o common.o
+fakesyn: fakesyn.o mon.o mds.o client.o osd.o ebofs.o osdc.o msg/FakeMessenger.o common.o crush/libcrush.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
 
 # mpi startup
-newsyn: newsyn.cc mon.o mds.o client.o osd.o ebofs.o osdc.o msg/SimpleMessenger.o common.o
+newsyn: newsyn.cc mon.o mds.o client.o osd.o ebofs.o osdc.o msg/SimpleMessenger.o common.o crush/libcrush.o
        ${MPICC} ${MPICFLAGS} ${MPILIBS} $^ -o $@
 
 
@@ -243,6 +243,14 @@ gprof-helper.so: test/gprof-helper.c
 test_disk_bw: test/test_disk_bw.cc common.o
        ${CC} ${CFLAGS} ${LIBS} $^ -o $@
 
+# crush
+
+crush/libcrush.o: force_look
+       cd crush ; make
+
+force_look:
+       true
+
 # bits
 common.o: ${COMMON_OBJS}
        ${LDINC} $@ $^
@@ -268,7 +276,6 @@ mon.o: ${MON_OBJS}
 osbdb.o: ${OSBDB_OBJS}
        ${LDINC} $@ $^
 
-
 # generic rules
 %.so: %.cc
        ${CC} -shared -fPIC ${CFLAGS} $< -o $@
diff --git a/trunk/ceph/crush.old/BinaryTree.h b/trunk/ceph/crush.old/BinaryTree.h
new file mode 100644 (file)
index 0000000..7573fc0
--- /dev/null
@@ -0,0 +1,285 @@
+// -*- 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 __crush_BINARYTREE_H
+#define __crush_BINARYTREE_H
+
+#include <cassert>
+#include <iostream>
+#include <map>
+#include <vector>
+using std::map;
+using std::vector;
+
+#include "include/buffer.h"
+
+namespace crush {
+
+  class BinaryTree {
+  private:
+    // tree def
+    int             root_node;       // 0 for empty tree.
+    int             alloc;
+    vector<int>     node_nested;     // all existing nodes in this map
+    vector<float>   node_weight;     // and this one
+    vector<int>     node_complete;   // only nodes with all possible children
+
+  public:
+    BinaryTree() : root_node(0), alloc(0) {}
+    
+    void _encode(bufferlist& bl) {
+      bl.append((char*)&root_node, sizeof(root_node));
+      bl.append((char*)&alloc, sizeof(alloc));
+      ::_encode(node_nested, bl);
+      ::_encode(node_weight, bl);
+      ::_encode(node_complete, bl);
+    }
+    void _decode(bufferlist& bl, int& off) {
+      bl.copy(off, sizeof(root_node), (char*)&root_node);
+      off += sizeof(root_node);
+      bl.copy(off, sizeof(alloc), (char*)&alloc);
+      off += sizeof(alloc);
+      ::_decode(node_nested, bl, off);
+      ::_decode(node_weight, bl, off);
+      ::_decode(node_complete, bl, off);
+    }
+
+    // accessors
+    bool  empty() const { return root_node == 0; }
+    bool  exists(int n) const { return n < alloc && node_nested[n]; }
+    int   nested(int n) const { return exists(n) ? node_nested[n]:0; }
+    float weight(int n) const { return exists(n) ? node_weight[n]:0; }
+    bool  complete(int n) const { return exists(n) ? node_complete[n]:false; }
+
+    int   root() const { return root_node; }
+    
+    void   realloc(int n) {
+        /*
+        while (alloc <= n) {
+          node_nested.push_back(0);
+          node_weight.push_back(0);
+          node_complete.push_back(0);
+          alloc++;
+        }
+        */
+      if (alloc <= n) {
+        int add = n - alloc + 1;
+        node_nested.insert(node_nested.end(), add, 0);
+        node_weight.insert(node_weight.end(), add, 0);
+        node_complete.insert(node_complete.end(), add, 0);
+        alloc = n+1;
+      }
+    }
+
+    // tree navigation
+    bool terminal(int n) const { return n & 1; }  // odd nodes are leaves.
+    int height(int n) const {
+      assert(n);
+      int h = 0;
+      while ((n & 1) == 0) {
+        assert(n > 0);
+        h++; n = n >> 1;
+      }
+      return h;
+    }
+    int left(int n) const { 
+      int h = height(n);
+      //cout << "left of " << n << " is " << (n - (1 << h)) << std::endl;
+      return n - (1 << (h-1));
+    }
+    int right(int n) const {
+      int h = height(n);
+      //cout << "right of " << n << " is " << (n + (1 << h)) << std::endl;
+      return n + (1 << (h-1));
+    }
+    bool on_right(int n, int h = -1) const { 
+      if (h < 0) h = height(n);
+      return n & (1 << (h+1)); 
+    }
+    bool on_left(int n) const { return !on_right(n); }
+    int parent(int n) const {
+      int h = height(n);
+      if (on_right(n, h))
+        return n - (1<<h);
+      else
+        return n + (1<<h);
+    }
+    
+    // modifiers
+    void adjust_node_weight(int n, float w) {
+      assert(exists(n));
+      node_weight[n] += w;
+     
+      int p = n;
+      while (p != root_node) {
+        p = parent(p);
+        node_weight[p] += w;
+      }
+    }
+
+    void remove_node(int n) {
+      assert(exists(n));
+      
+      // erase node
+      node_nested[n] = 0;
+      node_weight[n] = 0;
+
+      // adjust parents (!complete, -weight)
+      int p = n;
+      while (p != root_node) {
+        p = parent(p);
+
+        node_complete[p] = 0;
+        node_weight[p] = weight(left(p)) + weight(right(p));
+        node_nested[p]--;
+
+        if (nested(p) == 0) {
+          node_weight[p] = 0;
+          node_nested[p] = 0;
+        }
+      }
+      
+      // hose root?
+      while (!terminal(root_node) &&
+             (nested(left(root_node)) == 0 ||
+             nested(right(root_node)) == 0)) {
+        // root now one child..
+        node_weight[root_node] = 0;
+        node_nested[root_node] = 0;
+        if (nested(left(root_node)) == 0)
+          root_node = right(root_node);
+        else 
+          root_node = left(root_node);
+      }
+
+      if (terminal(root_node) && 
+          nested(root_node) == 0) {
+        // empty!
+        node_weight[root_node] = 0;
+        node_nested[root_node] = 0;
+        root_node = 0;
+      }
+
+    }
+
+    int add_node_root(float w) {
+      return add_node(w, true);
+    }
+    
+    int add_node(float w, bool force_root=false) {
+      int n;
+      if (!root_node) {
+        // empty tree!
+        root_node = n = 1;
+      } else {
+        // existing tree.
+        // expand tree?
+        if (force_root || complete(root_node)) {
+          // add new root
+          int newroot = parent(root_node);
+          realloc(newroot);
+          node_weight[newroot] = node_weight[root_node];
+          node_nested[newroot] = nested(root_node);
+
+          // go right or left?
+          if (left(newroot) == root_node)
+            n = right(newroot);
+          else
+            n = left(newroot);
+          root_node = newroot;
+
+          // then go left until terminal
+          while (!terminal(n))
+            n = left(n);
+        }
+        else {
+          // tree isn't complete.
+          n = root_node;
+          while (!terminal(n)) {
+            if (!exists(left(n)) || !complete(left(n))) {
+              // left isn't complete
+              n = left(n);
+            } else {
+              assert(!exists(right(n)) || !complete(right(n)));
+              // right isn't complete
+              n = right(n);
+            }
+          }
+        }
+      }
+      
+      // create at n
+      //cout << "creating " << n << std::endl;
+      realloc(n);
+      node_weight[n] = w;
+      node_nested[n] = 1;
+      node_complete[n] = 1;
+
+      // ancestors: create, adjust weight, complete as appropriate
+      int p = n;
+      while (p != root_node) {
+        p = parent(p);
+        realloc(p);
+
+        // complete?
+        if (!complete(p) &&
+            complete(left(p)) && 
+            complete(right(p))) 
+          node_complete[p] = 1;
+        
+        // weight (and implicitly create)
+        node_weight[p] += w;
+        node_nested[p]++;
+      }
+
+      return n;
+
+    }
+    
+
+  };
+
+
+  // print it out
+  inline void print_binary_tree_node(ostream& out, const BinaryTree& tree, int n, int i) {
+    for (int t=i; t>0; t--) out << "  ";
+    if (tree.root() == n)
+      out << "root  ";
+    else {
+      if (tree.on_left(n))
+        out << "left  ";
+      else
+        out << "right ";
+    }
+    out << n << " : nested " << tree.nested(n) << "   weight " << tree.weight(n);
+    if (tree.complete(n)) out << "  complete";
+    out << std::endl;
+    if (!tree.terminal(n)) {
+      if (tree.exists(tree.left(n)))
+        print_binary_tree_node(out, tree, tree.left(n), i+2);
+      if (tree.exists(tree.right(n)))
+        print_binary_tree_node(out, tree, tree.right(n), i+2);
+    }
+  }
+  
+  inline ostream& operator<<(ostream& out, const BinaryTree& tree) {
+    if (tree.empty()) 
+      return out << "tree is empty";
+    print_binary_tree_node(out, tree, tree.root(), 0);    
+    return out;
+  }
+  
+}
+
+#endif
diff --git a/trunk/ceph/crush.old/Bucket.h b/trunk/ceph/crush.old/Bucket.h
new file mode 100644 (file)
index 0000000..81a2576
--- /dev/null
@@ -0,0 +1,632 @@
+// -*- 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 __crush_BUCKET_H
+#define __crush_BUCKET_H
+
+#include "BinaryTree.h"
+#include "Hash.h"
+
+#include <list>
+#include <vector>
+#include <map>
+#include <set>
+using namespace std;
+
+#include <math.h>
+
+#include "include/buffer.h"
+
+namespace crush {
+
+
+  const int CRUSH_BUCKET_UNIFORM = 1;
+  const int CRUSH_BUCKET_TREE = 2;
+  const int CRUSH_BUCKET_LIST = 3;
+  const int CRUSH_BUCKET_STRAW = 4;
+
+  /** abstract bucket **/
+  class Bucket {
+  protected:
+    int         id;
+    int         parent;
+    int         type;
+    float       weight;
+
+  public:
+    Bucket(int _type,
+           float _weight) :
+      id(0), parent(0),
+      type(_type),
+      weight(_weight) { }
+
+    Bucket(bufferlist& bl, int& off) {
+      bl.copy(off, sizeof(id), (char*)&id);
+      off += sizeof(id);
+      bl.copy(off, sizeof(parent), (char*)&parent);
+      off += sizeof(parent);
+      bl.copy(off, sizeof(type), (char*)&type);
+      off += sizeof(type);
+      bl.copy(off, sizeof(weight), (char*)&weight);
+      off += sizeof(weight);
+    }
+
+    virtual ~Bucket() { }
+    
+    virtual const char *get_bucket_type() const = 0;
+    virtual bool is_uniform() const = 0;
+
+    int          get_id() const { return id; } 
+    int          get_type() const { return type; }
+    float        get_weight() const { return weight; }
+    int          get_parent() const { return parent; }
+    virtual int  get_size() const = 0;
+
+    void         set_id(int i) { id = i; }
+    void         set_parent(int p) { parent = p; }
+    void         set_weight(float w)  { weight = w; }
+
+    virtual void get_items(vector<int>& i) const = 0;
+    virtual float get_item_weight(int item) const = 0;
+    virtual void add_item(int item, float w, bool back=false) = 0;
+    virtual void adjust_item_weight(int item, float w) = 0;
+    virtual void set_item_weight(int item, float w) {
+      adjust_item_weight(item, w - get_item_weight(item));
+    }
+
+    virtual int choose_r(int x, int r, Hash& h) const = 0;
+
+    virtual void _encode(bufferlist& bl) = 0;
+  };
+
+
+
+
+  /** uniform bucket **/
+  class UniformBucket : public Bucket {    
+  protected:
+  public:
+    vector<int> items;
+    int    item_type;
+    float  item_weight;
+
+    // primes
+    vector<unsigned> primes;
+
+    int get_prime(int j) const {
+      return primes[ j % primes.size() ];
+    }
+    void make_primes() {
+      if (items.empty()) return;
+
+      //cout << "make_primes " << get_id() << " " << items.size() << endl;
+      Hash h(123+get_id());
+      primes.clear();
+
+      // start with odd number > num_items
+      unsigned x = items.size() + 1;             // this is the minimum!
+      x += h(items.size()) % (3*items.size());  // bump it up some
+      x |= 1;                               // make it odd
+
+      while (primes.size() < items.size()) {
+        unsigned j;
+        for (j=2; j*j<=x; j++) 
+          if (x % j == 0) break;
+        if (j*j > x) {
+          primes.push_back(x);
+          //cout << "prime " << x << endl;
+        }
+        x += 2;
+      }
+    }
+
+  public:
+    UniformBucket(int _type, int _item_type) :
+      Bucket(_type, 0),
+      item_type(_item_type) { }
+    UniformBucket(int _type, int _item_type,
+                  float _item_weight, vector<int>& _items) :
+      Bucket(_type, _item_weight*_items.size()),
+      item_type(_item_type),
+      item_weight(_item_weight) {
+      items = _items;
+      make_primes();
+    }
+
+    UniformBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+      bl.copy(off, sizeof(item_type), (char*)&item_type);
+      off += sizeof(item_type);
+      bl.copy(off, sizeof(item_weight), (char*)&item_weight);
+      off += sizeof(item_weight);
+      ::_decode(items, bl, off);
+      make_primes();
+    }
+
+    void _encode(bufferlist& bl) {
+      char t = CRUSH_BUCKET_UNIFORM;
+      bl.append((char*)&t, sizeof(t));
+      bl.append((char*)&id, sizeof(id));
+      bl.append((char*)&parent, sizeof(parent));
+      bl.append((char*)&type, sizeof(type));
+      bl.append((char*)&weight, sizeof(weight));
+
+      bl.append((char*)&item_type, sizeof(item_type));
+      bl.append((char*)&item_weight, sizeof(item_weight));
+
+      ::_encode(items, bl);
+    }
+
+    const char *get_bucket_type() const { return "uniform"; }
+    bool is_uniform() const { return true; }
+
+    int get_size() const { return items.size(); }
+
+    // items
+    void get_items(vector<int>& i) const {
+      i = items;
+    }
+    int get_item_type() const { return item_type; }
+    float get_item_weight(int item) const { return item_weight; }
+
+    void add_item(int item, float w, bool back=false) {
+      if (items.empty())
+        item_weight = w;
+      items.push_back(item);
+      weight += item_weight;
+      make_primes();
+    }
+
+    void adjust_item_weight(int item, float w) {
+      assert(0);
+    }
+
+    int choose_r(int x, int r, Hash& hash) const {
+      //cout << "uniformbucket.choose_r(" << x << ", " << r << ")" << endl;
+      //if (r >= get_size()) cout << "warning: r " << r << " >= " << get_size() << " uniformbucket.size" << endl;
+      
+      unsigned v = hash(x, get_id());// % get_size();
+      unsigned p = get_prime( hash(get_id(), x) );  // choose a prime based on hash(x, get_id(), 2)
+      unsigned s = (x + v + (r+1)*p) % get_size();
+      return items[s];
+    }
+
+  };
+
+
+
+
+  
+  // list bucket.. RUSH_P sorta
+  
+  class ListBucket : public Bucket {
+  protected:
+    list<int>        items;
+    list<float>      item_weight;
+    list<float>      sum_weight;
+    
+  public:
+    ListBucket(int _type) : Bucket(_type, 0) { }
+
+    ListBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+      ::_decode(items, bl, off);
+      ::_decode(item_weight, bl, off);
+      ::_decode(sum_weight, bl, off);
+    }
+
+    void _encode(bufferlist& bl) {
+      char t = CRUSH_BUCKET_LIST;
+      bl.append((char*)&t, sizeof(t));
+      bl.append((char*)&id, sizeof(id));
+      bl.append((char*)&parent, sizeof(parent));
+      bl.append((char*)&type, sizeof(type));
+      bl.append((char*)&weight, sizeof(weight));
+
+      ::_encode(items, bl);
+      ::_encode(item_weight, bl);
+      ::_encode(sum_weight, bl);
+    }
+
+    const char *get_bucket_type() const { return "list"; }
+    bool        is_uniform() const { return false; }
+
+    int get_size() const { return items.size(); }
+
+    void get_items(vector<int>& i) const {
+      for (list<int>::const_iterator it = items.begin();
+           it != items.end();
+           it++) 
+        i.push_back(*it);
+    }
+    float get_item_weight(int item) const {
+      list<int>::const_iterator i = items.begin();
+      list<float>::const_iterator w = item_weight.begin();
+      while (i != items.end()) {
+        if (*i == item) return *w;
+        i++; w++;
+      }
+      assert(0);
+      return 0;
+    }
+
+    void add_item(int item, float w, bool back=false) {
+      if (back) {
+        items.push_back(item);
+        item_weight.push_back(w);
+        sum_weight.clear();
+        float s = 0.0;
+        for (list<float>::reverse_iterator i = item_weight.rbegin();
+             i != item_weight.rend();
+             i++) {
+          s += *i;
+          sum_weight.push_front(s);
+        }
+        weight += w;
+        assert(weight == s);
+      } else {
+        items.push_front(item);
+        item_weight.push_front(w);
+        weight += w;
+        sum_weight.push_front(weight);
+      }
+    }
+
+    void adjust_item_weight(int item, float dw) {
+      // find it
+      list<int>::iterator p = items.begin();
+      list<float>::iterator pw = item_weight.begin();
+      list<float>::iterator ps = sum_weight.begin();
+
+      while (*p != item) {
+        *ps += dw;
+        p++; pw++; ps++;  // next!
+        assert(p != items.end());
+      }
+
+      assert(*p == item);
+      *pw += dw;
+      *ps += dw;
+    }
+
+    
+    int choose_r(int x, int r, Hash& h) const {
+      //cout << "linearbucket.choose_r(" << x << ", " << r << ")" << endl;
+
+      list<int>::const_iterator p = items.begin();
+      list<float>::const_iterator pw = item_weight.begin();
+      list<float>::const_iterator ps = sum_weight.begin();
+
+      while (p != items.end()) {
+        const int item = *p;
+        const float iw = *pw;
+        const float tw = *ps;
+        const float f = (float)(h(x, item, r, get_id()) % 10000) * tw / 10000.0;
+        //cout << "item " << item << "  iw = " << iw << "  tw = " << tw << "  f = " << f << endl;
+        if (f < iw) {
+          //cout << "linearbucket.choose_r(" << x << ", " << r << ") = " << item << endl;
+          return item;
+        }
+        p++; pw++; ps++;  // next!
+      }
+      assert(0);
+      return 0;
+    }    
+
+
+  };
+
+
+
+
+  // mixed bucket, based on RUSH_T type binary tree
+  
+  class TreeBucket : public Bucket {
+  protected:
+    //vector<float>  item_weight;
+
+    //  public:
+    BinaryTree     tree;
+    map<int,int>   node_item;     // node id -> item
+    vector<int>    node_item_vec; // fast version of above
+    map<int,int>   item_node;     // item -> node id
+    map<int,float> item_weight;
+
+  public:
+    TreeBucket(int _type) : Bucket(_type, 0) { }
+    
+    TreeBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+      tree._decode(bl, off);
+      
+      ::_decode(node_item, bl, off);
+      ::_decode(node_item_vec, bl, off);
+      ::_decode(item_node, bl, off);
+      ::_decode(item_weight, bl, off);
+    }
+
+    void _encode(bufferlist& bl) {
+      char t = CRUSH_BUCKET_TREE;
+      bl.append((char*)&t, sizeof(t));
+      bl.append((char*)&id, sizeof(id));
+      bl.append((char*)&parent, sizeof(parent));
+      bl.append((char*)&type, sizeof(type));
+      bl.append((char*)&weight, sizeof(weight));
+
+      tree._encode(bl);
+
+      ::_encode(node_item, bl);
+      ::_encode(node_item_vec, bl);
+      ::_encode(item_node, bl);
+      ::_encode(item_weight, bl);
+    }
+
+    const char *get_bucket_type() const { return "tree"; }
+    bool        is_uniform() const { return false; }
+
+    int get_size() const { return node_item.size(); }
+
+    // items
+    void get_items(vector<int>& i) const {
+      for (map<int,int>::const_iterator it = node_item.begin();
+           it != node_item.end();
+           it++) 
+        i.push_back(it->second);    
+    }
+    float get_item_weight(int i) const { 
+      assert(item_weight.count(i));
+      return ((map<int,float>)item_weight)[i]; 
+    }
+
+
+    void add_item(int item, float w, bool back=false) {
+      item_weight[item] = w;
+      weight += w;
+
+      unsigned n = tree.add_node(w);
+      node_item[n] = item;
+      item_node[item] = n;
+
+      while (node_item_vec.size() <= n) 
+        node_item_vec.push_back(0);
+      node_item_vec[n] = item;
+    }
+    
+    void adjust_item_weight(int item, float dw) {
+      // adjust my weight
+      weight += dw;
+      item_weight[item] += dw;
+
+      // adjust tree weights
+      tree.adjust_node_weight(item_node[item], dw);
+    }
+    
+    int choose_r(int x, int r, Hash& h) const {
+      //cout << "mixedbucket.choose_r(" << x << ", " << r << ")" << endl;
+      int n = tree.root();
+      while (!tree.terminal(n)) {
+        // pick a point in [0,w)
+        float w = tree.weight(n);
+        float f = (float)(h(x, n, r, get_id()) % 10000) * w / 10000.0;
+
+        // left or right?
+        int l = tree.left(n);
+        if (tree.exists(l) && 
+            f < tree.weight(l))
+          n = l;
+        else
+          n = tree.right(n);
+      }
+      //assert(node_item.count(n));
+      //return ((map<int,int>)node_item)[n];
+      return node_item_vec[n];
+    }
+  };
+
+
+
+
+
+  // straw bucket.. new thing!
+  
+  class StrawBucket : public Bucket {
+  protected:
+    map<int, float>  item_weight;
+    map<int, float>  item_straw;
+
+    list<int>   _items;
+    list<float> _straws;
+
+  public:
+    StrawBucket(int _type) : Bucket(_type, 0) { }
+
+    StrawBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
+      ::_decode(item_weight, bl, off);
+      calc_straws();
+    }
+
+    void _encode(bufferlist& bl) {
+      char t = CRUSH_BUCKET_TREE;
+      bl.append((char*)&t, sizeof(t));
+      bl.append((char*)&id, sizeof(id));
+      bl.append((char*)&parent, sizeof(parent));
+      bl.append((char*)&type, sizeof(type));
+      bl.append((char*)&weight, sizeof(weight));
+
+      ::_encode(item_weight, bl);
+    }
+
+    const char *get_bucket_type() const { return "straw"; }
+    bool is_uniform() const { return false; }
+
+    int get_size() const { return item_weight.size(); }
+
+
+    // items
+    void get_items(vector<int>& i) const {
+      for (map<int,float>::const_iterator it = item_weight.begin();
+           it != item_weight.end();
+           it++) 
+        i.push_back(it->first);
+    }
+    float get_item_weight(int item) const {
+      assert(item_weight.count(item));
+      return ((map<int,float>)item_weight)[item];
+    }
+
+    void add_item(int item, float w, bool back=false) {
+      item_weight[item] = w;
+      weight += w;
+      calc_straws();
+    }
+
+    void adjust_item_weight(int item, float dw) {
+      //cout << "adjust " << item << " " << dw << endl;
+      weight += dw;
+      item_weight[item] += dw;
+      calc_straws();
+    }
+    
+    
+    /* calculate straw lengths.
+       this is kind of ugly.  not sure if there's a closed form way to calculate this or not!    
+     */
+    void calc_straws() {
+      //cout << get_id() << ": calc_straws ============" << endl;
+
+      item_straw.clear();
+      _items.clear();
+      _straws.clear();
+
+      // reverse sort by weight; skip zero weight items
+      map<float, set<int> > reverse;
+      for (map<int, float>::iterator p = item_weight.begin();
+           p != item_weight.end();
+           p++) {
+        //cout << get_id() << ":" << p->first << " " << p->second << endl;
+        if (p->second > 0) {
+          //p->second /= minw;
+          reverse[p->second].insert(p->first);
+        }
+      }
+
+      /* 1:2:7 
+         item_straw[0] = 1.0;
+         item_straw[1] = item_straw[0]*sqrt(1.0/.6);
+         item_straw[2] = item_straw[1]*2.0;
+      */
+
+      // work from low to high weights
+      float straw = 1.0;
+      float numleft = item_weight.size();
+      float wbelow = 0.0;
+      float lastw = 0.0;
+      
+      map<float, set<int> >::iterator next = reverse.begin();
+      //while (next != reverse.end()) {
+      while (1) {
+        //cout << "hi " << next->first << endl;
+        map<float, set<int> >::iterator cur = next;
+        
+        // set straw length for this set
+        for (set<int>::iterator s = cur->second.begin();
+             s != cur->second.end();
+             s++) {
+          item_straw[*s] = straw;
+          //cout << "straw " << *s << " w " << item_weight[*s] << " -> " << straw << endl;
+          _items.push_back(*s);
+          _straws.push_back(straw);
+        }
+        
+        next++;
+        if (next == reverse.end()) break;
+        
+        wbelow += (cur->first-lastw) * numleft;
+        //cout << "wbelow " << wbelow << endl;
+        
+        numleft -= 1.0 * (float)cur->second.size();
+        //cout << "numleft now " << numleft << endl;
+        
+        float wnext = numleft * (next->first - cur->first);
+        //cout << "wnext " << wnext << endl;
+        
+        float pbelow = wbelow / (wbelow+wnext);
+        //cout << "pbelow " << pbelow << endl;
+        
+        straw *= pow((double)(1.0/pbelow), (double)1.0/numleft);
+        
+        lastw = cur->first;
+      }
+      //cout << "============" << endl;
+    }
+
+    int choose_r(int x, int r, Hash& h) const {
+      //cout << "strawbucket.choose_r(" << x << ", " << r << ")" << endl;
+
+      float high_draw = -1;
+      int high = 0;
+
+      list<int>::const_iterator pi = _items.begin();
+      list<float>::const_iterator ps = _straws.begin();
+      while (pi != _items.end()) {
+        const int item = *pi;
+        const float rnd = (float)(h(x, item, r) % 1000000) / 1000000.0;
+        const float straw = *ps * rnd;
+        
+        if (high_draw < 0 ||
+            straw > high_draw) {
+          high = *pi;
+          high_draw = straw;
+        }
+
+        pi++;
+        ps++;
+      }
+      return high;
+    }    
+  };
+
+
+
+
+
+  inline Bucket* decode_bucket(bufferlist& bl, int& off) {
+    char t;
+    bl.copy(off, sizeof(t), (char*)&t);
+    off += sizeof(t);
+
+    switch (t) {
+    case CRUSH_BUCKET_UNIFORM:
+      return new UniformBucket(bl, off);
+    case CRUSH_BUCKET_LIST:
+      return new ListBucket(bl, off);
+    case CRUSH_BUCKET_TREE:
+      return new TreeBucket(bl, off);
+    case CRUSH_BUCKET_STRAW:
+      return new StrawBucket(bl, off);
+    default:
+      assert(0);
+    }
+    return 0;
+  }
+
+
+
+}
+
+
+
+
+
+
+
+
+#endif
diff --git a/trunk/ceph/crush.old/Hash.h b/trunk/ceph/crush.old/Hash.h
new file mode 100644 (file)
index 0000000..2f0d9e4
--- /dev/null
@@ -0,0 +1,301 @@
+// -*- 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.
+ * 
+ */
+
+
+// Robert Jenkins' function for mixing 32-bit values
+// http://burtleburtle.net/bob/hash/evahash.html
+// a, b = random bits, c = input and output
+#define hashmix(a,b,c) \
+        a=a-b;  a=a-c;  a=a^(c>>13); \
+        b=b-c;  b=b-a;  b=b^(a<<8);  \
+        c=c-a;  c=c-b;  c=c^(b>>13); \
+        a=a-b;  a=a-c;  a=a^(c>>12); \
+        b=b-c;  b=b-a;  b=b^(a<<16); \
+        c=c-a;  c=c-b;  c=c^(b>>5);  \
+        a=a-b;  a=a-c;  a=a^(c>>3); \
+        b=b-c;  b=b-a;  b=b^(a<<10); \
+        c=c-a;  c=c-b;  c=c^(b>>15); 
+
+namespace crush {
+  
+  class Hash {
+    int seed;
+
+  public:
+    int get_seed() { return seed; }
+    void set_seed(int s) { seed = s; }
+
+    Hash(int s) {
+      unsigned int hash = 1315423911;
+      int x = 231232;
+      int y = 1232;
+      hashmix(s, x, hash);
+      hashmix(y, s, hash);
+      seed = s;
+    }
+
+    inline int operator()(int a) {
+      unsigned int hash = seed ^ a;
+      int b = a;
+      int x = 231232;
+      int y = 1232;
+      hashmix(b, x, hash);
+      hashmix(y, a, hash);
+      return (hash & 0x7FFFFFFF);
+    }
+
+    inline int operator()(int a, int b) {
+      unsigned int hash = seed ^ a ^ b;
+      int x = 231232;
+      int y = 1232;
+      hashmix(a, b, hash);
+      hashmix(x, a, hash);
+      hashmix(b, y, hash);
+      return (hash & 0x7FFFFFFF);
+    }
+
+    inline int operator()(int a, int b, int c) {
+      unsigned int hash = seed ^ a ^ b ^ c;
+      int x = 231232;
+      int y = 1232;
+      hashmix(a, b, hash);
+      hashmix(c, x, hash);
+      hashmix(y, a, hash);
+      hashmix(b, x, hash);
+      hashmix(y, c, hash);
+      return (hash & 0x7FFFFFFF);
+    }
+
+    inline int operator()(int a, int b, int c, int d) {
+      unsigned int hash = seed ^a ^ b ^ c ^ d;
+      int x = 231232;
+      int y = 1232;
+      hashmix(a, b, hash);
+      hashmix(c, d, hash);
+      hashmix(a, x, hash);
+      hashmix(y, b, hash);
+      hashmix(c, x, hash);
+      hashmix(y, d, hash);
+      return (hash & 0x7FFFFFFF);
+    }
+
+    inline int operator()(int a, int b, int c, int d, int e) {
+      unsigned int hash = seed ^ a ^ b ^ c ^ d ^ e;
+      int x = 231232;
+      int y = 1232;
+      hashmix(a, b, hash);
+      hashmix(c, d, hash);
+      hashmix(e, x, hash);
+      hashmix(y, a, hash);
+      hashmix(b, x, hash);
+      hashmix(y, c, hash);
+      hashmix(d, x, hash);
+      hashmix(y, e, hash);
+      return (hash & 0x7FFFFFFF);
+    }
+  };
+
+}
+
+
+
+#if 0
+
+
+      //return myhash(a) ^ seed;
+      return myhash(a, seed);
+    }
+    int operator()(int a, int b) {
+      //return myhash( myhash(a) ^ myhash(b) ^ seed );
+      return myhash(a, b, seed);
+    }
+    int operator()(int a, int b, int c) {
+      //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ seed );
+      return myhash(a, b, c, seed);
+    }
+    int operator()(int a, int b, int c, int d) {
+      //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ myhash(d ^ seed) ^ seed );
+      return myhash(a, b, c, d, seed);
+    }
+
+      // ethan's rush hash?
+      if (0) 
+        return (n ^ 0xdead1234) * (884811920 * 3  + 1);
+
+      if (1) {
+
+        // before
+        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+        hashmix(a, b, hash);
+        n = n >> 8;
+        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+        hashmix(a, b, hash);
+        n = n >> 8;
+        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+        hashmix(a, b, hash);
+        n = n >> 8;
+        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+        hashmix(a, b, hash);
+        n = n >> 8;
+
+        //return hash;
+        return (hash & 0x7FFFFFFF);
+      }
+
+      // JS
+      //  a little better than RS
+      //  + jenkin's mixing thing (which sucks on its own but helps tons here)
+      //  best so far
+      if (1) {
+        unsigned int hash = 1315423911;
+        int a = 231232;
+        int b = 1232;
+        
+        for(unsigned int i = 0; i < 4; i++)
+          {
+            hash ^= ((hash << 5) + (n&255) + (hash >> 2));
+            hashmix(a, b, hash);
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+      
+      // Robert jenkins' 96 bit mix
+      //  sucks
+      if (0) {
+        int c = n;
+        int a = 12378912;
+        int b = 2982827;
+        a=a-b;  a=a-c;  a=a^(c>>13); 
+        b=b-c;  b=b-a;  b=b^(a<<8);  
+        c=c-a;  c=c-b;  c=c^(b>>13); 
+        a=a-b;  a=a-c;  a=a^(c>>12); 
+        b=b-c;  b=b-a;  b=b^(a<<16); 
+        c=c-a;  c=c-b;  c=c^(b>>5);  
+        a=a-b;  a=a-c;  a=a^(c>>3); 
+        b=b-c;  b=b-a;  b=b^(a<<10); 
+        c=c-a;  c=c-b;  c=c^(b>>15); 
+        return c;
+      }
+      // robert jenkins 32-bit
+      //  sucks
+      if (0) {
+        n += (n << 12);
+        n ^= (n >> 22);
+        n += (n << 4);
+        n ^= (n >> 9);
+        n += (n << 10);
+        n ^= (n >> 2);
+        n += (n << 7);
+        n ^= (n >> 12);
+        return n;
+      }
+
+      // djb2
+      if (0) {
+        unsigned int hash = 5381;
+        for (int i=0; i<4; i++) {
+          hash = ((hash << 5) + hash) + ((n&255) ^ 123);
+          n = n >> 8;
+        }
+        return hash;
+      }
+
+
+      // SDBM
+      if (1) {
+        unsigned int hash = 0;
+        
+        for(unsigned int i = 0; i < 4; i++)
+          {
+            hash = (n&255) + (hash << 6) + (hash << 16) - hash;
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+      // PJW
+      //  horrid
+      if (0) {
+        unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
+        unsigned int ThreeQuarters     = (unsigned int)((BitsInUnsignedInt  * 3) / 4);
+        unsigned int OneEighth         = (unsigned int)(BitsInUnsignedInt / 8);
+        unsigned int HighBits          = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
+        unsigned int hash              = 0;
+        unsigned int test              = 0;
+        
+        for(unsigned int i = 0; i < 4; i++)
+          {
+            hash = (hash << OneEighth) + (n&255);
+            
+            if((test = hash & HighBits)  != 0)
+              {
+                hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
+              }
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+      // RS Hash function, from Robert Sedgwicks Algorithms in C book, w/ some changes.
+      if (0) {
+        unsigned int b    = 378551;
+        unsigned int a    = 63689;
+        unsigned int hash = 0;
+        
+        for(unsigned int i=0; i<4; i++)
+          {
+            hash = hash * a + (n&0xff);
+            a    = a * b;
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+      // DJB
+      //  worse than rs
+      if (0) {
+        unsigned int hash = 5381;
+        
+        for(unsigned int i = 0; i < 4; i++)
+          {
+            hash = ((hash << 5) + hash) + (n&255);
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+      // AP
+      //  even worse
+      if (1) {
+        unsigned int hash = 0;
+        
+        for(unsigned int i = 0; i < 4; i++)
+          {
+            hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ (n&255) ^ (hash >> 3)) :
+              (~((hash << 11) ^ (n&255) ^ (hash >> 5)));
+            n = n >> 8;
+          }
+        
+        return (hash & 0x7FFFFFFF);
+      }
+
+
+#endif
diff --git a/trunk/ceph/crush.old/crush.h b/trunk/ceph/crush.old/crush.h
new file mode 100644 (file)
index 0000000..376e7d9
--- /dev/null
@@ -0,0 +1,543 @@
+// -*- 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 __crush_CRUSH_H
+#define __crush_CRUSH_H
+
+#include <iostream>
+#include <list>
+#include <vector>
+#include <set>
+#include <map>
+using std::set;
+using std::map;
+using std::vector;
+using std::list;
+#include <ext/hash_map>
+#include <ext/hash_set>
+using namespace __gnu_cxx;
+
+
+#include "Bucket.h"
+
+#include "include/buffer.h"
+
+
+namespace crush {
+
+
+  // *** RULES ***
+
+  class RuleStep {
+  public:
+    int         cmd;
+    vector<int> args;
+
+    RuleStep(int c) : cmd(c) {}
+    RuleStep(int c, int a) : cmd(c) {
+      args.push_back(a);
+    }
+    RuleStep(int c, int a, int b) : cmd(c) {
+      args.push_back(a);
+      args.push_back(b);
+    }
+    RuleStep(int o, int a, int b, int c) : cmd(o) {
+      args.push_back(a);
+      args.push_back(b);
+      args.push_back(c);
+    }
+
+    void _encode(bufferlist& bl) {
+      bl.append((char*)&cmd, sizeof(cmd));
+      ::_encode(args, bl);
+    }
+    void _decode(bufferlist& bl, int& off) {
+      bl.copy(off, sizeof(cmd), (char*)&cmd);
+      off += sizeof(cmd);
+      ::_decode(args, bl, off);
+    }
+  };
+
+
+  // Rule operations
+  const int CRUSH_RULE_TAKE = 0;
+  const int CRUSH_RULE_CHOOSE = 1;         // first n by default
+  const int CRUSH_RULE_CHOOSE_FIRSTN = 1;
+  const int CRUSH_RULE_CHOOSE_INDEP = 2;
+  const int CRUSH_RULE_EMIT = 3;
+
+  class Rule {
+  public:
+    vector< RuleStep > steps;
+
+    void _encode(bufferlist& bl) {
+      int n = steps.size();
+      bl.append((char*)&n, sizeof(n));
+      for (int i=0; i<n; i++)
+        steps[i]._encode(bl);
+    }
+    void _decode(bufferlist& bl, int& off) {
+      steps.clear();
+      int n;
+      bl.copy(off, sizeof(n), (char*)&n);
+      off += sizeof(n);
+      for (int i=0; i<n; i++) {
+        steps.push_back(RuleStep(0));
+        steps[i]._decode(bl, off);
+      }
+    }
+  };
+
+
+
+
+  // *** CRUSH ***
+
+  class Crush {
+  protected:
+    map<int, Bucket*>  buckets;
+    int bucketno;
+    Hash h;
+
+    hash_map<int, int> parent_map;  // what bucket each leaf/bucket lives in
+
+  public:
+    map<int, Rule>     rules;
+
+    //map<int,int> collisions;
+    //map<int,int> bumps;    
+
+    void _encode(bufferlist& bl) {
+      // buckets
+      int n = buckets.size();
+      bl.append((char*)&n, sizeof(n));
+      for (map<int, Bucket*>::const_iterator it = buckets.begin();
+           it != buckets.end();
+           it++) {
+        bl.append((char*)&it->first, sizeof(it->first));
+        it->second->_encode(bl);
+      }
+      bl.append((char*)&bucketno, sizeof(bucketno));
+
+      // hash
+      int s = h.get_seed();
+      bl.append((char*)&s, sizeof(s));
+
+      //::_encode(out, bl);
+      //::_encode(overload, bl);
+      
+      // rules
+      n = rules.size();
+      bl.append((char*)&n, sizeof(n));
+      for(map<int, Rule>::iterator it = rules.begin();
+          it != rules.end();
+          it++) {
+        bl.append((char*)&it->first, sizeof(it->first));
+        it->second._encode(bl);
+      }
+        
+    }
+
+    void _decode(bufferlist& bl, int& off) {
+      int n;
+      bl.copy(off, sizeof(n), (char*)&n);
+      off += sizeof(n);
+      for (int i=0; i<n; i++) {
+        int bid;
+        bl.copy(off, sizeof(bid), (char*)&bid);
+        off += sizeof(bid);
+        Bucket *b = decode_bucket(bl, off);
+        buckets[bid] = b;
+      }
+      bl.copy(off, sizeof(bucketno), (char*)&bucketno);
+      off += sizeof(bucketno);
+
+      int s;
+      bl.copy(off, sizeof(s), (char*)&s);
+      off += sizeof(s);
+      h.set_seed(s);
+
+      //::_decode(out, bl, off);
+      //::_decode(overload, bl, off);
+
+      // rules
+      bl.copy(off, sizeof(n), (char*)&n);
+      off += sizeof(n);
+      for (int i=0; i<n; i++) {
+        int r;
+        bl.copy(off, sizeof(r), (char*)&r);
+        off += sizeof(r);
+        rules[r]._decode(bl,off);
+      }
+      
+      // index
+      build_parent_map();
+    }
+
+    void build_parent_map() {
+      parent_map.clear();
+      
+      // index every bucket
+      for (map<int, Bucket*>::iterator bp = buckets.begin();
+          bp != buckets.end();
+          ++bp) {
+       // index bucket items
+       vector<int> items;
+       bp->second->get_items(items);
+       for (vector<int>::iterator ip = items.begin();
+            ip != items.end();
+            ++ip)
+         parent_map[*ip] = bp->first;
+      }
+    }
+    
+
+
+  public:
+    Crush(int seed=123) : bucketno(-1), h(seed) {}
+    ~Crush() {
+      // hose buckets
+      for (map<int, Bucket*>::iterator it = buckets.begin();
+           it != buckets.end();
+           it++) {
+        delete it->second;
+      }
+    }
+
+    int print(ostream& out, int root, int indent=0) {
+      for (int i=0; i<indent; i++) out << " ";
+      Bucket *b = buckets[root];
+      assert(b);
+      out << b->get_weight() << "\t" << b->get_id() << "\t";
+      for (int i=0; i<indent; i++) out << " ";
+      out << b->get_bucket_type() << ": ";
+
+      vector<int> items;
+      b->get_items(items);
+
+      if (buckets.count(items[0])) {
+        out << std::endl;
+        for (unsigned i=0; i<items.size(); i++)
+          print(out, items[i], indent+1);
+      } else {
+        out << "[";
+        for (unsigned i=0; i<items.size(); i++) {
+          if (i) out << " ";
+          out << items[i];
+        }
+        out << "]";
+      }
+      return 0;
+    }
+
+
+    int add_bucket( Bucket *b ) {
+      int n = bucketno;
+      bucketno--;
+      b->set_id(n);
+      buckets[n] = b;
+      return n;
+    }
+
+    void add_item(int parent, int item, float w, bool back=false) {
+      // add item
+      assert(!buckets[parent]->is_uniform());
+      Bucket *p = buckets[parent];
+      
+      p->add_item(item, w, back);
+
+      // set item's parent
+      Bucket *n = buckets[item];
+      if (n)
+        n->set_parent(parent);
+
+      // update weights
+      while (buckets.count(p->get_parent())) {
+        int child = p->get_id();
+        p = buckets[p->get_parent()];
+        p->adjust_item_weight(child, w);
+      }
+    }
+
+
+    /*
+    this is a hack, fix me!  weights should be consistent throughout hierarchy!
+    
+     */
+    void set_bucket_weight(int item, float w) {
+      Bucket *b = buckets[item];
+      float adj = w - b->get_weight();
+
+      while (buckets.count(b->get_parent())) {
+        Bucket *p = buckets[b->get_parent()];
+        p->adjust_item_weight(b->get_id(), adj);
+        b = p;
+      }
+    }
+
+
+    /*
+     * choose numrep distinct items of type type
+     */
+    void choose(int x,
+                int numrep,
+                int type,
+                Bucket *inbucket,
+                vector<int>& outvec,
+                bool firstn,
+                set<int>& outset, map<int,float>& overloadmap,
+               bool forcefeed=false,
+               int forcefeedval=-1) {
+      int off = outvec.size();
+
+      // for each replica
+      for (int rep=0; rep<numrep; rep++) {
+        int outv = -1;                   // my result
+        
+       // forcefeed?
+       if (forcefeed) {
+         forcefeed = false;
+         outvec.push_back(forcefeedval);
+         continue;
+       }
+       
+        // keep trying until we get a non-out, non-colliding item
+        int ftotal = 0;
+        bool skip_rep = false;
+       
+        while (1) {
+          // start with the input bucket
+          Bucket *in = inbucket;
+          
+          // choose through intervening buckets
+          int flocal = 0;
+          bool retry_rep = false;
+
+          while (1) {
+            // r may be twiddled to (try to) avoid past collisions
+            int r = rep;
+            if (in->is_uniform()) {
+              // uniform bucket; be careful!
+              if (firstn || numrep >= in->get_size()) {
+                // uniform bucket is too small; just walk thru elements
+                r += ftotal;                    // r' = r + f_total (first n)
+              } else {
+                // make sure numrep is not a multple of bucket size
+                int add = numrep*flocal;        // r' = r + n*f_local
+                if (in->get_size() % numrep == 0) {
+                  add += add/in->get_size();         // shift seq once per pass through the bucket
+                }
+                r += add;
+              }
+            } else {
+              // mixed bucket; just make a distinct-ish r sequence
+              if (firstn)
+                r += ftotal;          // r' = r + f_total
+              else
+                r += numrep * flocal; // r' = r + n*f_local
+            }
+            
+            // choose
+            outv = in->choose_r(x, r, h);                     
+            
+            // did we get the type we want?
+            int itemtype = 0;          // 0 is terminal type
+            Bucket *newin = 0;         // remember bucket we hit
+            if (in->is_uniform()) {
+              itemtype = ((UniformBucket*)in)->get_item_type();
+            } else {
+              if (buckets.count(outv)) {  // another bucket
+                newin = buckets[outv];
+                itemtype = newin->get_type();
+              } 
+            }
+            if (itemtype == type) { // this is what we want!
+              // collision?
+              bool collide = false;
+              for (int prep=0; prep<rep; prep++) {
+                if (outvec[off+prep] == outv) {
+                  collide = true;
+                  break;
+                }
+              }
+
+              // ok choice?
+              bool bad = false;
+              if (type == 0 && outset.count(outv)) 
+                bad = true;
+              if (overloadmap.count(outv)) {
+                float f = (float)(h(x, outv) % 1000) / 1000.0;
+                if (f > overloadmap[outv])
+                  bad = true;
+              }
+
+              if (collide || bad) {
+                ftotal++;
+                flocal++;
+                
+                if (collide && flocal < 3) 
+                  continue;  // try locally a few times!
+                
+                if (ftotal >= 10) {
+                  // ok fine, just ignore dup.  FIXME.
+                  skip_rep = true;
+                  break;
+                }
+                
+                retry_rep = true;
+              }
+
+              break;  // ok then!
+            }
+
+            // next
+            in = newin;
+          }
+          
+          if (retry_rep) continue;  // try again
+
+          break;
+        }
+
+        // skip this rep? (e.g. too many collisions, we give up)
+        if (skip_rep) continue; 
+
+        // output this value
+        outvec.push_back(outv);
+      } // for rep
+
+      // double check!
+      if (0) {
+        for (unsigned i=1; i<outvec.size(); i++) 
+          for (unsigned j=0; j<i; j++)
+            assert(outvec[i] != outvec[j]);
+      }
+    }
+
+
+    void do_rule(Rule& rule, int x, vector<int>& result,
+                 set<int>& outset, map<int,float>& overloadmap,
+                int forcefeed=-1) {
+      //int numresult = 0;
+      result.clear();
+
+      // determine hierarchical context for forcefeed (if any)
+      list<int> force_stack;
+      if (forcefeed >= 0 && parent_map.count(forcefeed)) {
+       int t = forcefeed;
+       while (1) {
+         force_stack.push_front(t);
+         //cout << "push " << t << " onto force_stack" << std::endl;
+         if (parent_map.count(t) == 0) break;  // reached root, presumably.
+         //cout << " " << t << " parent is " << parent_map[t] << std::endl;
+         t = parent_map[t];
+       }
+      }
+      
+      // working vector
+      vector<int> w;   // working variable
+      
+      // go through each statement
+      for (vector<RuleStep>::iterator pc = rule.steps.begin();
+           pc != rule.steps.end();
+           pc++) {
+        // move input?
+        
+        // do it
+        switch (pc->cmd) {
+        case CRUSH_RULE_TAKE:
+          {    
+           const int arg = pc->args[0];
+           //cout << "take " << arg << std::endl;            
+           
+           if (!force_stack.empty()) {
+             assert(force_stack.front() == arg);
+             force_stack.pop_front();
+           }
+           
+           w.clear();
+           w.push_back(arg);
+          }
+          break;
+          
+        case CRUSH_RULE_CHOOSE_FIRSTN:
+        case CRUSH_RULE_CHOOSE_INDEP:
+          {
+            const bool firstn = pc->cmd == CRUSH_RULE_CHOOSE_FIRSTN;
+            const int numrep = pc->args[0];
+            const int type = pc->args[1];
+
+            //cout << "choose " << numrep << " of type " << type << std::endl;
+
+            assert(!w.empty());
+
+            // reset output
+            vector<int> out;
+
+            // forcefeeding?
+           bool forcing = false;
+           int forceval = -1;
+           if (!force_stack.empty()) {
+             forceval = force_stack.front();
+             force_stack.pop_front();
+             //cout << "priming out with " << forceval << std::endl;
+             forcing = true;
+           } else if (forcefeed >= 0 && type == 0) {
+             //cout << "forcing context-less " << forcefeed << std::endl;
+             forceval = forcefeed;
+             forcefeed = -1;
+             forcing = true;
+           }
+           
+            // do each row independently
+            for (vector<int>::iterator i = w.begin();
+                 i != w.end();
+                 i++) {
+              assert(buckets.count(*i));
+              Bucket *b = buckets[*i];
+             choose(x, numrep, type, b, out, firstn,
+                    outset, overloadmap,
+                    forcing,
+                    forceval);
+             forcing = false;  // only once
+            } // for inrow
+            
+            // put back into w
+            w.swap(out);
+            out.clear();
+          }
+          break;
+
+        case CRUSH_RULE_EMIT:
+          {
+            for (unsigned i=0; i<w.size(); i++)
+              result.push_back(w[i]);
+            //result[numresult++] = w[i];
+            w.clear();
+          }
+          break;
+
+        default:
+          assert(0);
+        }
+      }
+
+    }
+
+
+  };
+
+}
+
+#endif
diff --git a/trunk/ceph/crush.old/test/bucket_movement.cc b/trunk/ceph/crush.old/test/bucket_movement.cc
new file mode 100644 (file)
index 0000000..6be1735
--- /dev/null
@@ -0,0 +1,166 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       //if (bad)
+       // cout << "bad set " << x << ": " << v << endl;
+       
+       placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int n, float f, int buckettype)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+  int ndisks = 0;
+
+  // bucket
+  Bucket *b;
+  if (buckettype == 0)
+       b = new TreeBucket(1);
+  else if (buckettype == 1 || buckettype == 2)
+       b = new ListBucket(1);
+  else if (buckettype == 3)
+       b = new StrawBucket(1);
+  else if (buckettype == 4)
+       b = new UniformBucket(0,0);
+
+  for (int i=0; i<n; i++)
+       b->add_item(ndisks++,1);
+
+  c.add_bucket(b);
+  int root = b->get_id();
+  
+  //c.print(cout,root);
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 1000;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, vector<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  
+  // ORIGINAL
+  place(c, rule, numpg, numrep, placement1);
+  
+  int olddisks = ndisks;
+
+  // add item
+  if (buckettype == 2) {
+       // start over!
+       ndisks = 0;
+       b = new ListBucket(1);
+       for (int i=0; i<=n; i++)
+         b->add_item(ndisks++,1);
+       c.add_bucket(b);
+       root = b->get_id();
+
+       rule.steps.clear();
+       rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+       rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+       rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  }
+  else
+       b->add_item(ndisks++, 1);
+
+
+  // ADDED
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  int moved = 0;
+  for (int x=1; x<=numpg; x++) 
+       if (placement1[x] != placement2[x]) 
+         for (int j=0; j<numrep; j++)
+               if (placement1[x][j] != placement2[x][j]) 
+                 moved++;
+
+  int total = numpg*numrep;
+  float actual = (float)moved / (float)(total);
+  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+  float fac = actual/ideal;
+  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+  cout << "\t" << fac;
+  return fac;
+}
+
+
+int main() 
+{
+  //cout << "//  " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
+  cout << "n\ttree\tlhead\tltail\tstraw\tuniform" << endl;
+
+  //for (int s=2; s<=64; s+= (s<4?1:(s<16?2:4))) {
+  for (int s=2; s<=64; s+= (s<4?1:4)) {
+       float f = 1.0 / (float)s;
+       //cout << f << "\t" << s;
+       cout << s;
+       for (int buckettype=0; buckettype<5; buckettype++)
+         testmovement(s, f, buckettype);
+       cout << endl;
+  }
+}
+
diff --git a/trunk/ceph/crush.old/test/bucket_variance.cc b/trunk/ceph/crush.old/test/bucket_variance.cc
new file mode 100644 (file)
index 0000000..d2f553f
--- /dev/null
@@ -0,0 +1,199 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       //Bucket *b = new MixedBucket(h+1);
+       Bucket *b = new StrawBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+float go(int dep) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  if (0) {
+       for (int d=0; d<dep; d++)
+         wid.push_back(10);
+  }
+  if (1) {
+       if (dep == 0) 
+         wid.push_back(1000);
+       if (dep == 1) {
+         wid.push_back(1);
+         wid.push_back(1000);
+       }
+       if (dep == 2) {
+         wid.push_back(5);
+         wid.push_back(5);
+         wid.push_back(8);
+         wid.push_back(5);
+       }       
+  }
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  if (0) {
+       MixedBucket *b = new MixedBucket(1);
+       for (int i=0; i<10000; i++)
+         b->add_item(ndisks++, 10);
+       root = c.add_bucket(b);
+  }
+  if (0) {
+       vector<int> disks;
+       for (int i=0; i<10000; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+       Hash h(123);
+       b->make_primes(h);
+       root = c.add_bucket(b);
+  }
+  
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 100000;
+  int times = place / numpg;
+  if (!times) times = 1;
+
+  cout << "#looping " << times << " times" << endl;
+  
+  float tvar = 0;
+  int tvarnum = 0;
+
+  int x = 0;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       for (int xx=1; xx<numpg; xx++) {
+         x++;
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         if (bad)
+               cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       
+       /*
+         for (int i=0; i<ocount.size(); i++) {
+         cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       */
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       
+       float avg = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         avg += ocount[i];
+       avg /= ocount.size();
+       float var = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         var += (ocount[i] - avg) * (ocount[i] - avg);
+       var /= ocount.size();
+       
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       //cout << avg << "\t";
+       
+       tvar += var;
+       tvarnum++;
+  }
+
+  tvar /= tvarnum;
+
+  //cout << "total variance " << tvar << endl;
+
+  return tvar;
+}
+
+
+int main() 
+{
+  for (int d=0; d<=2; d++) {
+       float var = go(d);
+       //cout << "## depth = " << d << endl;
+       cout << d << "\t" << var << "\t" << sqrt(var) << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/cluster_movement.cc b/trunk/ceph/crush.old/test/cluster_movement.cc
new file mode 100644 (file)
index 0000000..aa1418a
--- /dev/null
@@ -0,0 +1,217 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int buckettype = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       //Bucket *b = new TreeBucket(h+1);
+       //Bucket *b = new ListBucket(h+1);
+       //Bucket *b = new StrawBucket(h+1);
+       Bucket *b;
+       if (buckettype == 0)
+         b = new TreeBucket(h+1);
+       else if (buckettype == 1 || buckettype == 2)
+         b = new ListBucket(h+1);
+       else if (buckettype == 3)
+         b = new StrawBucket(h+1);
+
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       
+       placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(udisks);
+  for (int d=1; d<depth; d++)
+       wid.push_back(branching);
+
+  map< int, list<Bucket*> > buckets;
+
+  root = make_hierarchy(c, wid, buckets, ndisks);
+  
+  //c.print(cout,root);
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, vector<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  
+  // ORIGINAL
+  place(c, rule, numpg, numrep, placement1);
+  
+  int olddisks = ndisks;
+
+  // add disks
+  //cout << " adding " << add << " disks" << endl;
+  vector<int> disks;
+  for (int i=0; i<add; i++)
+       disks.push_back(ndisks++);
+  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+  //b->make_primes(h);
+
+  //Bucket *o = buckets[2].back();
+  Bucket *o;
+  if (buckettype == 2)
+       o = buckets[modifydepth].front();
+  else
+       o = buckets[modifydepth].back();
+
+  c.add_bucket(b);
+  //cout << " adding under " << o->get_id() << endl;
+  c.add_item(o->get_id(), b->get_id(), b->get_weight());
+  //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+  //newbucket = b;
+
+
+  // ADDED
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  int moved = 0;
+  for (int x=1; x<=numpg; x++) 
+       if (placement1[x] != placement2[x]) 
+         for (int j=0; j<numrep; j++)
+               if (placement1[x][j] != placement2[x][j]) 
+                 moved++;
+
+  int total = numpg*numrep;
+  float actual = (float)moved / (float)(total);
+  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+  float fac = actual/ideal;
+  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+  cout << "\t" << fac;
+  return fac;
+}
+
+
+int main() 
+{
+  
+  int udisks = 10;
+  int add = udisks;
+
+  //int depth = 3;
+  //int branching = 25;
+  int depth = 4;
+  int branching = 9;
+
+  int modifydepth = 1;
+  int bfac = (int)(sqrt((double)branching));
+  int n = (int)(udisks * pow((float)branching, (float)depth-1));
+
+  cout << "// depth " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
+  cout << "n\ttree\tlhead\tltail\tstraw" << endl;
+  for (int add = udisks; add <= n; add *= bfac) {
+       cout << add;
+       for (buckettype=0; buckettype<4; buckettype++)
+         testmovement(depth, branching, udisks, add, modifydepth);
+       cout << endl;
+  }
+}
+
diff --git a/trunk/ceph/crush.old/test/cluster_movement_remove.cc b/trunk/ceph/crush.old/test/cluster_movement_remove.cc
new file mode 100644 (file)
index 0000000..4a6560e
--- /dev/null
@@ -0,0 +1,229 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int buckettype = 2;  // 0 = mixed, 1 = linear, 2 = straw
+
+int big_one_skip = 255;
+int big_one_size;
+Bucket *big_one = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       
+       int s = wid[h];
+       if (big_one_skip > 0) 
+         big_one_skip--;         
+       if (!big_one_skip && !big_one)
+         s = big_one_size;
+
+
+       for (int i=0; i<s; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       if (!big_one_skip && !big_one) big_one = b;
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks " << disks.size()<< endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       Bucket *b;
+       if (buckettype == 0)
+         b = new TreeBucket(h+1);
+       else if (buckettype == 1)
+         b = new ListBucket(h+1);
+       else if (buckettype == 2)
+         b = new StrawBucket(h+1);
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       if (bad)
+         cout << "bad set " << x << ": " << v << endl;
+       
+       placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(udisks);
+  for (int d=1; d<depth; d++)
+       wid.push_back(branching + ((d==2)?1:0));
+
+  map< int, list<Bucket*> > buckets;
+
+  big_one_size = add;
+  big_one = 0;
+  
+  //cout << "making tree" << endl;
+  root = make_hierarchy(c, wid, buckets, ndisks);
+  
+  //c.print(cout, root);
+
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, vector<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  int olddisks = ndisks;
+
+
+  place(c, rule, numpg, numrep, placement1);
+  
+  if (1) {
+       // remove disks
+       assert(big_one);
+       c.adjust_item(big_one->get_id(), 0);
+  }
+
+  int newdisks = ndisks - add;
+
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  int moved = 0;
+  for (int x=1; x<=numpg; x++) 
+       if (placement1[x] != placement2[x]) 
+         for (int j=0; j<numrep; j++)
+               if (placement1[x][j] != placement2[x][j]) 
+                 moved++;
+
+  int total = numpg*numrep;
+  float actual = (float)moved / (float)(total);
+  //float ideal = (float)(newdisks-olddisks) / (float)(ndisks);
+  float ideal = (float)(olddisks-newdisks) / (float)(olddisks);
+  float fac = actual/ideal;
+  cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+  return fac;
+}
+
+
+int main() 
+{
+  
+  int udisks = 10;
+  int ndisks = 10;
+  int depth = 4;
+  int branching = 9;
+  int add = udisks;
+
+  //cout << "\t" << n;
+  //  cout << endl;
+
+  buckettype = 2;  // 0 = tree, 1 = linear, 2 = straw
+
+  int n = udisks * pow((float)branching, (float)depth-1);
+  for (int add = udisks; add <= n; add *= 3) {
+       big_one_skip = 0;
+       big_one_skip = 9;
+       testmovement(depth, branching, udisks, add);
+  }
+  
+  /*
+  cout << "##" << endl;
+  for (map<int, map<float,float> >::iterator i = r.begin();
+          i != r.end();
+          i++) {
+       cout << i->first;
+       for (map<float,float>::iterator j = i->second.begin();
+                j != i->second.end();
+                j++)
+         cout << "\t" << j->first << "\t" << j->second;
+       cout << endl;
+  }
+  */
+}
+
diff --git a/trunk/ceph/crush.old/test/cluster_movement_rush.cc b/trunk/ceph/crush.old/test/cluster_movement_rush.cc
new file mode 100644 (file)
index 0000000..90cc197
--- /dev/null
@@ -0,0 +1,218 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+int buckettype = 0;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       //Bucket *b = new TreeBucket(h+1);
+       //Bucket *b = new ListBucket(h+1);
+       //Bucket *b = new StrawBucket(h+1);
+       Bucket *b;
+       if (buckettype == 0)
+         b = new TreeBucket(h+1);
+       else if (buckettype == 1 || buckettype == 2)
+         b = new ListBucket(h+1);
+       else if (buckettype == 3)
+         b = new StrawBucket(h+1);
+
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       
+       placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(udisks);
+  for (int d=1; d<depth; d++)
+       wid.push_back(branching);
+
+  map< int, list<Bucket*> > buckets;
+
+  root = make_hierarchy(c, wid, buckets, ndisks);
+  
+  //c.print(cout,root);
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, vector<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  
+  // ORIGINAL
+  place(c, rule, numpg, numrep, placement1);
+  
+  int olddisks = ndisks;
+
+  // add disks
+  //cout << " adding " << add << " disks" << endl;
+  vector<int> disks;
+  for (int i=0; i<add; i++)
+       disks.push_back(ndisks++);
+  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+  //b->make_primes(h);
+
+  //Bucket *o = buckets[2].back();
+  Bucket *o;
+  if (buckettype == 2)
+       o = buckets[modifydepth].front();
+  else
+       o = buckets[modifydepth].back();
+
+  c.add_bucket(b);
+  //cout << " adding under " << o->get_id() << endl;
+  c.add_item(o->get_id(), b->get_id(), b->get_weight(), buckettype == 2);
+  //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+  //newbucket = b;
+
+
+  // ADDED
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  int moved = 0;
+  for (int x=1; x<=numpg; x++) 
+       if (placement1[x] != placement2[x]) 
+         for (int j=0; j<numrep; j++)
+               if (placement1[x][j] != placement2[x][j]) 
+                 moved++;
+
+  int total = numpg*numrep;
+  float actual = (float)moved / (float)(total);
+  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+  float fac = actual/ideal;
+  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
+  cout << "\t" << fac;
+  return fac;
+}
+
+
+int main() 
+{
+  
+  int udisks = 10;
+  int add = udisks;
+
+  //int depth = 3;
+  //int branching = 25;
+  int depth = 2;
+  int branching = 9*9*9;
+
+  int modifydepth = 1;
+  int bfac = (int)(sqrt((double)branching));
+  bfac = 3;
+  int n = (int)(udisks * pow((float)branching, (float)depth-1));
+
+  cout << "// depth " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
+  cout << "n\ttree\tlhead\tltail\tstraw" << endl;
+  for (int add = udisks; add <= n; add *= bfac) {
+       cout << add;
+       for (buckettype=0; buckettype<3; buckettype++)
+         testmovement(depth, branching, udisks, add, modifydepth);
+       cout << endl;
+  }
+}
+
diff --git a/trunk/ceph/crush.old/test/creeping_failure.cc b/trunk/ceph/crush.old/test/creeping_failure.cc
new file mode 100644 (file)
index 0000000..ce27535
--- /dev/null
@@ -0,0 +1,276 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include "../../common/Clock.h"
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Clock g_clock;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       float w = 10;//((ndisks-1)/100+1)*10;
+       UniformBucket *b = new UniformBucket(1, 0, w, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b = new TreeBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+
+float go(int dep, int failpc) 
+{
+  Hash h(73232313);
+
+  //int overloadcutoff = (int)((float)10000.0 / (float)utilization);
+
+  //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  for (int d=0; d<dep; d++)
+       wid.push_back(10);
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+
+  //cout << ndisks << " disks" << endl;
+
+
+  int numf = ndisks * failpc / 100;
+
+
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+  int pg_per_base = 100;//20;
+  int pg_med = 10*pg_per_base;
+  int pg_per = pg_per_base*5.5;//100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 1000000;
+  int times = place / numpg;
+  if (!times) times = 1;
+  
+
+  //cout << "looping " << times << " times" << endl;
+  
+  float tavg[10];
+  float tvar[10];
+  for (int j=0;j<10;j++) {
+       tvar[j] = 0;
+       tavg[j] = 0;
+  }
+  int tvarnum = 0;
+  float trvar = 0.0;
+
+  float overloadsum = 0.0;
+  float adjustsum = 0.0;
+  float afteroverloadsum = 0.0;
+  float aslowdown = 0.0;
+  int chooses = 0;
+  int xs = 1;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       c.out.clear();
+
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+       
+       utime_t t1a = g_clock.now();
+       for (int x=xs; x<numpg+xs; x++) {
+         c.do_rule(rule, x, v);
+         //chooses += numrep;
+         for (int i=0; i<v.size(); i++) {
+               //if (v[i] >= ndisks) cout << "v[i] " << i << " is " << v[i] << "  .. x = " << x << endl;
+               //assert(v[i] < ndisks);
+               ocount[v[i]]++;
+         }
+       }
+       utime_t t1b = g_clock.now();
+
+       // add in numf failed disks
+       for (int f = 0; f < numf; f++) {
+         int d = rand() % ndisks;
+         while (c.out.count(d)) d = rand() % ndisks;
+         c.out.insert(d);
+       }
+
+       utime_t t3a = g_clock.now();
+       for (int x=xs; x<numpg+xs; x++) {
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         for (int i=0; i<v.size(); i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+         }
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       xs += numpg;
+
+       utime_t t3b = g_clock.now();
+
+       t1b -= t1a;
+       double t1 = (double)t1b;
+       t3b -= t3a;
+       double t3 = (double)t3b;
+       double slowdown = t3/t1;
+       //cout << "slowdown " << slowdown << endl;
+       aslowdown += slowdown;
+
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       // stair var calc
+       int n = ndisks/10;
+       float avg[10];
+       float var[10];
+       for (int i=0;i<10;i++) {
+         int s = n*i;
+         avg[i] = 0.0;
+         int nf = 0;
+         for (int j=0; j<n; j++) {
+               if (c.out.count(j+s)) { nf++; continue; }
+               avg[i] += ocount[j+s];
+         }
+         avg[i] /= (n-nf);//ocount.size();
+         var[i] = 0.0;
+         for (int j=0; j<n; j++) {
+               if (c.out.count(j+s)) continue;
+               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+         }
+         var[i] /= (n-nf);//ocount.size();
+
+         tvar[i] += var[i];
+         tavg[i] += avg[i];
+       }
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       
+       tvarnum++;
+
+       // flat var calc
+       int na = ndisks - numf;  // num active
+       float ravg = 0.0;
+       for (int i=0;i<ndisks;i++) {
+         if (c.out.count(i)) continue;
+         ravg += ocount[i];
+       }
+       ravg /= (float)na;
+       float rvar = 0.0;
+       for (int i=0; i<ndisks; i++) {
+         if (c.out.count(i)) continue;
+         rvar += (ravg-(float)ocount[i])*(ravg-(float)ocount[i]);
+       }
+       rvar /= (float)na;
+
+       trvar += rvar;
+  }
+
+
+  trvar /= (float)tvarnum;
+
+  //overloadsum /= tvarnum;
+  //adjustsum /= tvarnum;
+  float avar = 0.0;
+  for (int j=0;j<10;j++) {
+       tvar[j] /= tvarnum;
+       tavg[j] /= tvarnum;
+       avar += tvar[j];
+  }
+  avar /= 10;
+  avar = sqrt(avar);
+  avar /= /*5.5 **/ (float)pg_per_base;
+  //afteroverloadsum /= tvarnum;
+  aslowdown /= tvarnum;
+
+  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+  //float crate = (float) collisions / (float)chooses;
+  //cout << "collisions: " << c.collisions << endl;
+
+
+  //cout << "total variance " << tvar << endl;
+  //cout << " overlaod " << overloadsum << endl;
+  
+  cout << failpc 
+          << "\t" << numf 
+       //<< "\t" << adjustsum 
+       //<< "\t" << afteroverloadsum 
+          << "\t" << aslowdown 
+          << "\t" << trvar
+          << "\t" << sqrt(trvar) / (float)pg_per_base
+          << "\t..\t" << avar 
+          << "\t-"; 
+
+  for (int i=0;i<10;i++)
+       cout << "\t" << tavg[i] << "\t" << sqrt(tvar[i]);// << "\t" << tvar[i]/tavg[i];
+
+  cout << endl;
+  return tvar[0];
+}
+
+
+int main() 
+{
+  for (int pc = 0; pc < 90; pc += 5) {
+       float var = go(3, pc);
+  }
+  
+
+}
diff --git a/trunk/ceph/crush.old/test/creeping_failure_variance.cc b/trunk/ceph/crush.old/test/creeping_failure_variance.cc
new file mode 100644 (file)
index 0000000..c7a65a0
--- /dev/null
@@ -0,0 +1,281 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       MixedBucket *b = new MixedBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
+{
+  int w = rand() % (wid-1) + 2;
+
+  if (height == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<w; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       int h = rand() % height + 1;
+       MixedBucket *b = new MixedBucket(h+1);
+       for (int i=0; i<w; i++) {
+         Bucket *n = make_random(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+
+}
+
+
+float go(int dep, int overloadcutoff) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  for (int d=0; d<dep; d++)
+       wid.push_back(10);
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  if (0) {
+       Bucket *r = make_random(c, 20,  4, ndisks);
+       root = r->get_id();
+       //c.print(cout, root);
+  }
+  if (0) {
+       MixedBucket *b = new MixedBucket(1);
+       for (int i=0; i<10000; i++)
+         b->add_item(ndisks++, 10);
+       root = c.add_bucket(b);
+  }
+  if (0) {
+       vector<int> disks;
+       for (int i=0; i<10000; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+       Hash h(123);
+       b->make_primes(h);
+       root = c.add_bucket(b);
+  }
+  //cout << ndisks << " disks" << endl;
+  
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 1000000;
+  int times = place / numpg;
+  if (!times) times = 1;
+  
+
+  //cout << "looping " << times << " times" << endl;
+  
+  float tvar = 0;
+  int tvarnum = 0;
+
+  float overloadsum = 0.0;
+  float adjustsum = 0.0;
+  float afteroverloadsum = 0.0;
+  int chooses = 0;
+  int xs = 1;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       c.overload.clear();
+
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         chooses += numrep;
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         if (bad)
+               cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+
+       // overloaded?
+       int overloaded = 0;
+       int adjusted = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         if (ocount[i] > overloadcutoff) 
+               overloaded++;
+
+         if (ocount[i] > 100+(overloadcutoff-100)/2) {
+               adjusted++;
+               c.overload[i] = 100.0 / (float)ocount[i];
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+         ocount[i] = 0;
+       }
+       //cout << overloaded << " overloaded" << endl;
+       overloadsum += (float)overloaded / (float)ndisks;
+       adjustsum += (float)adjusted / (float)ndisks;
+
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         if (bad)
+               cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       xs += numpg;
+
+       int still = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         if (ocount[i] > overloadcutoff) {
+               still++;
+               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       }
+       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+       afteroverloadsum += (float)still / (float)ndisks;
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       float avg = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         avg += ocount[i];
+       avg /= ocount.size();
+       float var = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         var += (ocount[i] - avg) * (ocount[i] - avg);
+       var /= ocount.size();
+       
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       
+       tvar += var;
+       tvarnum++;
+  }
+
+  overloadsum /= tvarnum;
+  adjustsum /= tvarnum;
+  tvar /= tvarnum;
+  afteroverloadsum /= tvarnum;
+
+  int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+  float crate = (float) collisions / (float)chooses;
+  //cout << "collisions: " << c.collisions << endl;
+
+
+  //cout << "total variance " << tvar << endl;
+  //cout << " overlaod " << overloadsum << endl;
+
+  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
+  return tvar;
+}
+
+
+int main() 
+{
+  for (int d=140; d>100; d -= 5) {
+       float var = go(3,d);
+       //cout << "## depth = " << d << endl;
+       //cout << d << "\t" << var << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/depth_variance.cc b/trunk/ceph/crush.old/test/depth_variance.cc
new file mode 100644 (file)
index 0000000..7d60eba
--- /dev/null
@@ -0,0 +1,185 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b = new TreeBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+float go(int dep) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  if (1) {
+       for (int d=0; d<dep; d++)
+         wid.push_back(10);
+  }
+  if (0) {
+       if (dep == 0) 
+         wid.push_back(1000);
+       if (dep == 1) {
+         wid.push_back(1);
+         wid.push_back(1000);
+       }
+       if (dep == 2) {
+         wid.push_back(5);
+         wid.push_back(5);
+         wid.push_back(8);
+         wid.push_back(5);
+       }       
+  }
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 100000;
+  int times = place / numpg;
+  if (!times) times = 1;
+
+  cout << "#looping " << times << " times" << endl;
+  
+  float tvar = 0;
+  int tvarnum = 0;
+  float tavg = 0;
+
+  int x = 0;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       for (int xx=1; xx<numpg; xx++) {
+         x++;
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       
+       /*
+         for (int i=0; i<ocount.size(); i++) {
+         cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       */
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       
+       float avg = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         avg += ocount[i];
+       avg /= ocount.size();
+       float var = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         var += (ocount[i] - avg) * (ocount[i] - avg);
+       var /= ocount.size();
+       
+       if (times < 10) 
+         cout << "avg " << avg << "   evar " << sqrt(avg) << "   sd " << sqrt(var) << endl;
+       //cout << avg << "\t";
+       
+       tvar += var;
+       tavg += avg;
+       tvarnum++;
+  }
+
+  tavg /= tvarnum;
+  tvar /= tvarnum;
+
+  cout << "total variance " << sqrt(tvar) << "   expected " << sqrt(tavg) << endl;
+
+  return tvar;
+}
+
+
+int main() 
+{
+  for (int d=2; d<=5; d++) {
+       float var = go(d);
+       //cout << "## depth = " << d << endl;
+       //cout << d << "\t" << var << "\t" << sqrt(var) << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/mixed.cc b/trunk/ceph/crush.old/test/mixed.cc
new file mode 100644 (file)
index 0000000..5666f7b
--- /dev/null
@@ -0,0 +1,300 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       float w = ((ndisks-1)/100+1)*10;
+       UniformBucket *b = new UniformBucket(1, 0, w, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b = new TreeBucket(h+1);
+       //Bucket *b = new StrawBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+
+float go(int dep, int overloadcutoff) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  for (int d=0; d<dep; d++)
+       wid.push_back(10);
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per_base = 10;
+  int pg_per = pg_per_base*5.5;//100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 100000;
+  int times = place / numpg;
+  if (!times) times = 1;
+  
+
+  //cout << "looping " << times << " times" << endl;
+  
+  float tavg[10];
+  float tvar[10];
+  for (int j=0;j<10;j++) {
+       tvar[j] = 0;
+       tavg[j] = 0;
+  }
+  int tvarnum = 0;
+
+  float overloadsum = 0.0;
+  float adjustsum = 0.0;
+  float afteroverloadsum = 0.0;
+  int chooses = 0;
+  int xs = 1;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       c.overload.clear();
+
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         chooses += numrep;
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         //if (bad)
+         //cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+
+       // overloaded?
+       int overloaded = 0;
+       int adjusted = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         int target = (i/100+1)*10;
+         int cutoff = target * overloadcutoff / 100;
+         int adjoff = target + (cutoff - target)*3/4;
+         if (ocount[i] > cutoff) 
+               overloaded++;
+
+         if (ocount[i] > adjoff) {
+               adjusted++;
+               c.overload[i] = (float)target / (float)ocount[i];
+               //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+         ocount[i] = 0;
+       }
+       //cout << overloaded << " overloaded" << endl;
+       overloadsum += (float)overloaded / (float)ndisks;
+       adjustsum += (float)adjusted / (float)ndisks;
+
+
+
+       if (1) {
+         // second pass
+         for (int x=xs; x<numpg+xs; x++) {
+               
+               //cout << H(x) << "\t" << h(x) << endl;
+               c.do_rule(rule, x, v);
+               //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+               
+               bool bad = false;
+               for (int i=0; i<numrep; i++) {
+                 //int d = b.choose_r(x, i, h);
+                 //v[i] = d;
+                 ocount[v[i]]++;
+                 for (int j=i+1; j<numrep; j++) {
+                       if (v[i] == v[j]) 
+                         bad = true;
+                 }
+               }
+               
+               //cout << v << "\t" << ocount << endl;
+         }
+
+         for (int i=0; i<ocount.size(); i++) {
+               int target = (i/100+1)*10;
+               int cutoff = target * overloadcutoff / 100;
+               int adjoff = cutoff;//target + (cutoff - target)*3/4;
+
+               if (ocount[i] >= adjoff) {
+                 adjusted++;
+                 if (c.overload.count(i) == 0) {
+                       c.overload[i] = 1.0;
+                       adjusted++;
+                 }
+                 //else cout << "(re)adjusting " << i << endl;
+                 c.overload[i] *= (float)target / (float)ocount[i];
+                 //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+                 //cout << "disk " << i << " has " << ocount[i] << endl;
+               }
+               ocount[i] = 0;
+         }
+       }
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         //cout << v << "\t" << ocount << endl;
+       }
+       xs += numpg;
+
+       int still = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         int target = (i/100+1)*10;
+         int cutoff = target * overloadcutoff / 100;
+         int adjoff = target + (cutoff - target)/3;
+
+         if (ocount[i] > cutoff) {
+               still++;
+               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+               if (c.overload.count(i)) cout << "[adjusted] ";
+               cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       }
+       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+       afteroverloadsum += (float)still / (float)ndisks;
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       int n = ndisks/10;
+       float avg[10];
+       float var[10];
+       for (int i=0;i<10;i++) {
+         int s = n*i;
+         avg[i] = 0.0;
+         for (int j=0; j<n; j++)
+               avg[i] += ocount[j+s];
+         avg[i] /= n;//ocount.size();
+         var[i] = 0.0;
+         for (int j=0; j<n; j++)
+               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+         var[i] /= n;//ocount.size();
+
+         tvar[i] += var[i];
+         tavg[i] += avg[i];
+       }
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       
+       tvarnum++;
+  }
+
+  overloadsum /= tvarnum;
+  adjustsum /= tvarnum;
+  for (int j=0;j<10;j++) {
+       tvar[j] /= tvarnum;
+       tavg[j] /= tvarnum;
+  }
+  afteroverloadsum /= tvarnum;
+
+  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+  //float crate = (float) collisions / (float)chooses;
+  //cout << "collisions: " << c.collisions << endl;
+
+
+  //cout << "total variance " << tvar << endl;
+  //cout << " overlaod " << overloadsum << endl;
+  
+  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum;
+  for (int i=0;i<10;i++)
+       cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
+  cout << endl;
+  return tvar[0];
+}
+
+
+int main() 
+{
+  float var = go(3,200);
+  for (int d=140; d>100; d -= 5) {
+       float var = go(3,d);
+       //cout << "## depth = " << d << endl;
+       //cout << d << "\t" << var << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/movement.cc b/trunk/ceph/crush.old/test/movement.cc
new file mode 100644 (file)
index 0000000..2621f09
--- /dev/null
@@ -0,0 +1,223 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       MixedBucket *b = new MixedBucket(h+1);
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       if (bad)
+         cout << "bad set " << x << ": " << v << endl;
+       
+       placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(udisks);
+  for (int d=1; d<depth; d++)
+       wid.push_back(branching);
+
+  map< int, list<Bucket*> > buckets;
+
+  if (1) {
+       root = make_hierarchy(c, wid, buckets, ndisks);
+  }
+  if (0) {
+       MixedBucket *b = new MixedBucket(1);
+       for (int i=0; i<10000; i++)
+         b->add_item(ndisks++, 10);
+       root = c.add_bucket(b);
+  }
+  if (0) {
+       vector<int> disks;
+       for (int i=0; i<10000; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       Hash h(123);
+       b->make_primes(h);
+       root = c.add_bucket(b);
+  }
+  
+
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, vector<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  place(c, rule, numpg, numrep, placement1);
+  
+  if (1) {
+       // failed
+
+       //for (int i=500; i<1000; i++)
+       //c.failed.insert(i);
+       c.failed.insert(0);
+  }
+
+  int olddisks = ndisks;
+
+  if (1) {
+       int n = udisks;
+       //cout << " adding " << n << " disks" << endl;
+       vector<int> disks;
+       for (int i=0; i<n; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       Hash h(123);
+       b->make_primes(h);
+       Bucket *o = buckets[1].back();
+       c.add_bucket(b);
+       //cout << " adding under " << o->get_id() << endl;
+       c.add_item(o->get_id(), b->get_id(), b->get_weight());
+       //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+  }
+
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  int moved = 0;
+  for (int x=1; x<=numpg; x++) {
+       if (placement1[x] != placement2[x]) {
+         for (int j=0; j<numrep; j++)
+               if (placement1[x][j] != placement2[x][j]) 
+                 moved++;
+         
+       }
+  }
+
+  float f = (float)moved / (float)(numpg*numrep);
+  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+  float fac = f/ideal;
+  //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac <<  endl;
+  return fac;
+}
+
+
+int main() 
+{
+  
+  int udisks = 10;
+  int ndisks = 10;
+  for (int depth = 2; depth <= 4; depth++) {
+       vector<float> v;
+       cout << depth;
+       for (int branching = 3; branching < 16; branching += 1) {
+         float fac = testmovement(depth, branching, udisks);
+         v.push_back(fac);
+       int n = udisks * pow((float)branching, (float)depth-1);
+       cout << "\t" << n;
+         cout << "\t" << fac;
+       }
+       //for (int i=0; i<v.size(); i++)
+       //cout << "\t" << v[i];
+       cout << endl;
+
+  }
+
+}
+
diff --git a/trunk/ceph/crush.old/test/movement_failed.cc b/trunk/ceph/crush.old/test/movement_failed.cc
new file mode 100644 (file)
index 0000000..98c34d9
--- /dev/null
@@ -0,0 +1,246 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       MixedBucket *b = new MixedBucket(h+1);
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, set<int> >& placement)
+{
+  vector<int> v(numrep);
+  map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+         placement[v[i]].insert(x);
+       }
+       if (bad)
+         cout << "bad set " << x << ": " << v << endl;
+       
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+  if (0) 
+       for (map<int,int>::iterator it = ocount.begin();
+                it != ocount.end();
+                it++) 
+         cout << it->first << "\t" << it->second << endl;
+
+}
+
+
+float testmovement(int depth, int branching, int udisks)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(udisks);
+  for (int d=1; d<depth; d++)
+       wid.push_back(branching);
+
+  map< int, list<Bucket*> > buckets;
+
+  if (1) {
+       root = make_hierarchy(c, wid, buckets, ndisks);
+  }
+  if (0) {
+       MixedBucket *b = new MixedBucket(1);
+       for (int i=0; i<10000; i++)
+         b->add_item(ndisks++, 10);
+       root = c.add_bucket(b);
+  }
+  if (0) {
+       vector<int> disks;
+       for (int i=0; i<10000; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       Hash h(123);
+       b->make_primes(h);
+       root = c.add_bucket(b);
+  }
+  
+
+
+  // rule
+  int numrep = 2;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  /*
+  cout << ndisks << " disks, " << endl;
+  cout << pg_per << " pgs per disk" << endl;
+    cout << numpg << " logical pgs" << endl;
+  cout << "numrep is " << numrep << endl;
+  */
+  map<int, set<int> > placement1, placement2;
+
+  //c.print(cout, root);
+
+  place(c, rule, numpg, numrep, placement1);
+
+  float over = .5;
+  
+  if (1) {
+       // failed
+
+       //for (int i=500; i<1000; i++)
+       //c.failed.insert(i);
+       //c.failed.insert(0);
+       c.overload[0] = over;
+  }
+
+  int olddisks = ndisks;
+
+
+
+  if (0) {
+       int n = udisks;
+       //cout << " adding " << n << " disks" << endl;
+       vector<int> disks;
+       for (int i=0; i<n; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       Hash h(123);
+       b->make_primes(h);
+       Bucket *o = buckets[1].back();
+       c.add_bucket(b);
+       //cout << " adding under " << o->get_id() << endl;
+       c.add_item(o->get_id(), b->get_id(), b->get_weight());
+       //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
+  }
+
+  //c.print(cout, root);
+  place(c, rule, numpg, numrep, placement2);
+
+  vector<int> moved(ndisks);
+
+  //int moved = 0;
+  for (int d=0; d<ndisks; d++) {
+       for (set<int>::iterator it = placement1[d].begin();
+                it != placement1[d].end();
+                it++) {
+         placement2[d].erase(*it);
+       }
+  }
+
+  float avg = 0;
+  for (int d=0; d<ndisks; d++) {
+       moved[d] = placement2[d].size();
+       avg += moved[d];
+  }
+  avg /= (float)ndisks;
+  float var = 0;
+  for (int d=0; d<ndisks; d++) {
+       var += (moved[d]-avg)*(moved[d]-avg);
+  }
+  var /= (float)ndisks;
+
+  float expected = over * 100.0 / (float)(ndisks-1);
+
+  cout << ndisks << "\t" << expected << "\t" << avg << "\t" << var << endl;
+  /*
+  float f = (float)moved / (float)(numpg*numrep);
+  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
+  float fac = f/ideal;
+  //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac <<  endl;
+  return fac;
+  */
+}
+
+
+int main() 
+{
+  
+  int udisks = 10;
+  int ndisks = 10;
+  for (int depth = 2; depth <= 4; depth++) {
+       vector<float> v;
+       cout << depth;
+       for (int branching = 3; branching < 16; branching += 1) {
+         float fac = testmovement(depth, branching, udisks);
+         v.push_back(fac);
+         int n = udisks * pow((float)branching, (float)depth-1);
+         //cout << "\t" << n;
+         //cout << "\t" << fac;
+       }
+       //for (int i=0; i<v.size(); i++)
+       //cout << "\t" << v[i];
+       //cout << endl;
+
+  }
+
+}
+
diff --git a/trunk/ceph/crush.old/test/overload.cc b/trunk/ceph/crush.old/test/overload.cc
new file mode 100644 (file)
index 0000000..32c6672
--- /dev/null
@@ -0,0 +1,335 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include "../../common/Clock.h"
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Clock g_clock;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       float w = ((ndisks-1)/100+1)*10;
+       UniformBucket *b = new UniformBucket(1, 0, w, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b = new TreeBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+
+float go(int dep, int utilization ) 
+{
+  Hash h(73232313);
+
+  int overloadcutoff = (int)((float)10000.0 / (float)utilization);
+
+  //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  for (int d=0; d<dep; d++)
+       wid.push_back(10);
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+
+  //cout << ndisks << " disks" << endl;
+  
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+  int pg_per_base = 20;
+  int pg_med = 10*pg_per_base;
+  int pg_per = pg_per_base*5.5;//100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 100000;
+  int times = place / numpg;
+  if (!times) times = 1;
+  
+
+  //cout << "looping " << times << " times" << endl;
+  
+  float tavg[10];
+  float tvar[10];
+  for (int j=0;j<10;j++) {
+       tvar[j] = 0;
+       tavg[j] = 0;
+  }
+  int tvarnum = 0;
+
+  float overloadsum = 0.0;
+  float adjustsum = 0.0;
+  float afteroverloadsum = 0.0;
+  float aslowdown = 0.0;
+  int chooses = 0;
+  int xs = 1;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       c.overload.clear();
+
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       
+       utime_t t1a = g_clock.now();
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         chooses += numrep;
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+         }
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+
+       utime_t t1b = g_clock.now();
+
+       // overloaded?
+       int overloaded = 0;
+       int adjusted = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         int target = (i/100+1)*pg_per_base;
+         int cutoff = target * overloadcutoff / 100;
+         int adjoff = target + (cutoff - target)*3/4;
+         if (ocount[i] > cutoff) 
+               overloaded++;
+
+         if (ocount[i] > adjoff) {
+               adjusted++;
+               c.overload[i] = (float)target / (float)ocount[i];
+               //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+         ocount[i] = 0;
+       }
+       //cout << overloaded << " overloaded" << endl;
+       overloadsum += (float)overloaded / (float)ndisks;
+       adjustsum += (float)adjusted / (float)ndisks;
+
+
+
+       // keep adjusting!
+       for (int bla=0; bla<5; bla++) {
+         utime_t t2a = g_clock.now();
+
+         // second pass
+         for (int x=xs; x<numpg+xs; x++) {
+               
+               //cout << H(x) << "\t" << h(x) << endl;
+               c.do_rule(rule, x, v);
+               //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+               
+               for (int i=0; i<numrep; i++) {
+                 //int d = b.choose_r(x, i, h);
+                 //v[i] = d;
+                 ocount[v[i]]++;
+               }
+               
+               //cout << v << "\t" << ocount << endl;
+         }
+
+         utime_t t2b = g_clock.now();
+
+         int numover = 0;
+         for (int i=0; i<ocount.size(); i++) {
+               int target = (i/100+1)*pg_per_base;
+               int cutoff = target * overloadcutoff / 100;
+               int adjoff = cutoff;//target + (cutoff - target)*3/4;
+
+               if (ocount[i] >= adjoff) {
+                 numover++;
+                 if (c.overload.count(i) == 0) {
+                       c.overload[i] = 1.0;
+                       adjusted++;
+                 }
+                 //else cout << "(re)adjusting " << i << endl;
+                 c.overload[i] *= (float)target / (float)ocount[i];
+                 //cout << "setting overload " << i << " to " << c.overload[i] << endl;
+                 //cout << "disk " << i << " has " << ocount[i] << endl;
+               }
+               ocount[i] = 0;
+         }
+         if (!numover) break;
+         cout << "readjusting" << endl;
+       }
+
+       utime_t t3a = g_clock.now();
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+         }
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       xs += numpg;
+
+       utime_t t3b = g_clock.now();
+
+       t1b -= t1a;
+       double t1 = (double)t1b;
+       t3b -= t3a;
+       double t3 = (double)t3b;
+       double slowdown = t3/t1;
+       //cout << "slowdown " << slowdown << endl;
+       aslowdown += slowdown;
+
+       int still = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         int target = (i/100+1)*pg_per_base;
+         int cutoff = target * overloadcutoff / 100;
+         //int adjoff = target + (cutoff - target)/3;
+
+         if (ocount[i] > cutoff) {
+               still++;
+               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+               if (c.overload.count(i)) cout << "[adjusted] ";
+               cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       }
+       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+       afteroverloadsum += (float)still / (float)ndisks;
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       int n = ndisks/10;
+       float avg[10];
+       float var[10];
+       for (int i=0;i<10;i++) {
+         int s = n*i;
+         avg[i] = 0.0;
+         for (int j=0; j<n; j++)
+               avg[i] += ocount[j+s];
+         avg[i] /= n;//ocount.size();
+         var[i] = 0.0;
+         for (int j=0; j<n; j++)
+               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
+         var[i] /= n;//ocount.size();
+
+         tvar[i] += var[i];
+         tavg[i] += avg[i];
+       }
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       
+       tvarnum++;
+  }
+
+  overloadsum /= tvarnum;
+  adjustsum /= tvarnum;
+  float avar = 0.0;
+  for (int j=0;j<10;j++) {
+       tvar[j] /= tvarnum;
+       tavg[j] /= tvarnum;
+       avar += tvar[j];
+  }
+  avar /= 10;
+  avar = sqrt(avar);
+  avar /= 5.5 * (float)pg_per_base;
+  afteroverloadsum /= tvarnum;
+  aslowdown /= tvarnum;
+
+  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+  //float crate = (float) collisions / (float)chooses;
+  //cout << "collisions: " << c.collisions << endl;
+
+
+  //cout << "total variance " << tvar << endl;
+  //cout << " overlaod " << overloadsum << endl;
+  
+  cout << overloadcutoff << "\t" << utilization 
+          << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum 
+          << "\t" << aslowdown << "\t" << avar << "\t-"; 
+
+  for (int i=0;i<10;i++)
+       cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
+  cout << endl;
+  return tvar[0];
+}
+
+
+int main() 
+{
+  float var = go(3,50);
+  /*  for (int d=70; d<100; d += 5) {
+       float var = go(3,d);
+       //cout << "## depth = " << d << endl;
+       //cout << d << "\t" << var << endl;
+       }*/
+  go(3,96);
+  go(3,97);
+  go(3,98);
+  go(3,99);
+  
+
+}
diff --git a/trunk/ceph/crush.old/test/overload_variance.cc b/trunk/ceph/crush.old/test/overload_variance.cc
new file mode 100644 (file)
index 0000000..b04cae0
--- /dev/null
@@ -0,0 +1,281 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       MixedBucket *b = new MixedBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
+{
+  int w = rand() % (wid-1) + 2;
+
+  if (height == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<w; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       int h = rand() % height + 1;
+       MixedBucket *b = new MixedBucket(h+1);
+       for (int i=0; i<w; i++) {
+         Bucket *n = make_random(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+
+}
+
+
+float go(int dep, int overloadcutoff) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  for (int d=0; d<dep; d++)
+       wid.push_back(10);
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  if (0) {
+       Bucket *r = make_random(c, 20,  4, ndisks);
+       root = r->get_id();
+       //c.print(cout, root);
+  }
+  if (0) {
+       MixedBucket *b = new MixedBucket(1);
+       for (int i=0; i<10000; i++)
+         b->add_item(ndisks++, 10);
+       root = c.add_bucket(b);
+  }
+  if (0) {
+       vector<int> disks;
+       for (int i=0; i<10000; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
+       Hash h(123);
+       b->make_primes(h);
+       root = c.add_bucket(b);
+  }
+  //cout << ndisks << " disks" << endl;
+  
+
+
+  // rule
+  int numrep = 1;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+
+  int pg_per = 100;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+  //cout << ndisks << " disks, " << endl;
+  //cout << pg_per << " pgs per disk" << endl;
+  //  cout << numpg << " logical pgs" << endl;
+  //cout << "numrep is " << numrep << endl;
+
+
+  int place = 1000000;
+  int times = place / numpg;
+  if (!times) times = 1;
+  
+
+  //cout << "looping " << times << " times" << endl;
+  
+  float tvar = 0;
+  int tvarnum = 0;
+
+  float overloadsum = 0.0;
+  float adjustsum = 0.0;
+  float afteroverloadsum = 0.0;
+  int chooses = 0;
+  int xs = 1;
+  for (int t=0; t<times; t++) {
+       vector<int> v(numrep);
+       
+       c.overload.clear();
+
+       for (int z=0; z<ndisks; z++) ocount[z] = 0;
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         chooses += numrep;
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         if (bad)
+               cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+
+       // overloaded?
+       int overloaded = 0;
+       int adjusted = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         if (ocount[i] > overloadcutoff) 
+               overloaded++;
+
+         if (ocount[i] > 100+(overloadcutoff-100)/2) {
+               adjusted++;
+               c.overload[i] = 100.0 / (float)ocount[i];
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+         ocount[i] = 0;
+       }
+       //cout << overloaded << " overloaded" << endl;
+       overloadsum += (float)overloaded / (float)ndisks;
+       adjustsum += (float)adjusted / (float)ndisks;
+
+
+       for (int x=xs; x<numpg+xs; x++) {
+
+         //cout << H(x) << "\t" << h(x) << endl;
+         c.do_rule(rule, x, v);
+         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+         
+         bool bad = false;
+         for (int i=0; i<numrep; i++) {
+               //int d = b.choose_r(x, i, h);
+               //v[i] = d;
+               ocount[v[i]]++;
+               for (int j=i+1; j<numrep; j++) {
+                 if (v[i] == v[j]) 
+                       bad = true;
+               }
+         }
+         if (bad)
+               cout << "bad set " << x << ": " << v << endl;
+         
+         //cout << v << "\t" << ocount << endl;
+       }
+       xs += numpg;
+
+       int still = 0;
+       for (int i=0; i<ocount.size(); i++) {
+         if (ocount[i] > overloadcutoff) {
+               still++;
+               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
+               //cout << "disk " << i << " has " << ocount[i] << endl;
+         }
+       }
+       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
+       afteroverloadsum += (float)still / (float)ndisks;
+       
+       //cout << "collisions: " << c.collisions << endl;
+       //cout << "r bumps: " << c.bumps << endl;
+       
+       float avg = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         avg += ocount[i];
+       avg /= ocount.size();
+       float var = 0.0;
+       for (int i=0; i<ocount.size(); i++)
+         var += (ocount[i] - avg) * (ocount[i] - avg);
+       var /= ocount.size();
+       
+       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
+       
+       tvar += var;
+       tvarnum++;
+  }
+
+  overloadsum /= tvarnum;
+  adjustsum /= tvarnum;
+  tvar /= tvarnum;
+  afteroverloadsum /= tvarnum;
+
+  int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
+  float crate = (float) collisions / (float)chooses;
+  //cout << "collisions: " << c.collisions << endl;
+
+
+  //cout << "total variance " << tvar << endl;
+  //cout << " overlaod " << overloadsum << endl;
+
+  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
+  return tvar;
+}
+
+
+int main() 
+{
+  for (int d=140; d>100; d -= 5) {
+       float var = go(3,d);
+       //cout << "## depth = " << d << endl;
+       //cout << d << "\t" << var << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/sizes.cc b/trunk/ceph/crush.old/test/sizes.cc
new file mode 100644 (file)
index 0000000..cc57802
--- /dev/null
@@ -0,0 +1,131 @@
+
+#include "include/types.h"
+#include "include/Distribution.h"
+#include "osd/OSDMap.h"
+
+
+Distribution file_size_distn; //kb
+
+
+list<int> object_queue;
+int max_object_size = 1024*1024*100;  //kb
+
+off_t no;
+
+int get_object()  //kb
+{
+  if (object_queue.empty()) {
+       int max = file_size_distn.sample();
+       no++;
+       int filesize = max/2 + (rand() % 100) * max/200 + 1;
+       //cout << "file " << filesize << endl;
+       while (filesize > max_object_size) {
+         object_queue.push_back(max_object_size);
+         filesize -= max_object_size;
+       }
+       object_queue.push_back(filesize);
+  }
+  int s = object_queue.front();
+  object_queue.pop_front();
+  //cout << "object " << s << endl;
+  return s;
+}
+
+void getdist(vector<off_t>& v, float& avg, float& var) 
+{
+  avg = 0.0;
+  for (int i=0; i<v.size(); i++)
+       avg += v[i];
+  avg /= v.size();
+  
+  var = 0.0;
+  for (int i=0; i<v.size(); i++)
+       var += (v[i] - avg) * (v[i] - avg);
+  var /= v.size();
+}
+
+
+void testpgs(int n, // numpg
+                        off_t pggb,
+                        float& avg,
+                        float& var,
+                        off_t& numo
+                        )
+{
+  off_t dist = (off_t)n * 1024LL*1024LL * (off_t)pggb;  //kb
+  vector<off_t> pgs(n);
+  off_t did = 0;
+  
+  no = 0;
+  while (did < dist) {
+       off_t s = get_object();
+       pgs[rand()%n] += s;
+       did += s;
+  }
+  while (!object_queue.empty())
+       pgs[rand()%n] += get_object();
+
+  numo = no;
+  //cout << did/n << endl; 
+
+  //for (int i=0; i<n; i++) cout << pgs[i] << endl;
+
+  getdist(pgs, avg, var);
+  //cout << "avg " << avg << "  var " << var << "  dev " << sqrt(var) << endl;
+}
+
+
+
+int main()
+{
+  /*
+
+// File Size 
+//cate   count_mean             size_mean       
+1b      -0.5     0.65434375     0        
+1k      0.5      19.0758125     0.00875          
+512K    1.5      35.6566        2.85875
+1M      2.5      27.7271875     25.0084375       
+2M      3.5      16.63503125    20.8046875       
+4M      4.5      106.82384375   296.053125       
+8M      5.5      81.493375      335.77625        
+16M     6.5      14.13553125    185.9775         
+32M     7.5      2.176          52.921875
+256M    8.5      0.655938       47.8066
+512M    9.5      0.1480625      57.83375 
+2G      10.5     0.020125       19.2888 
+  */
+  file_size_distn.add(1, 19.0758125+0.65434375);
+  file_size_distn.add(512, 35.6566);
+  file_size_distn.add(1024, 27.7271875);
+  file_size_distn.add(2*1024, 16.63503125);
+  file_size_distn.add(4*1024, 106.82384375);
+  file_size_distn.add(8*1024, 81.493375);
+  file_size_distn.add(16*1024, 14.13553125);
+  file_size_distn.add(32*1024, 2.176);
+  file_size_distn.add(256*1024, 0.655938);
+  file_size_distn.add(512*1024, 0.1480625);
+  file_size_distn.add(1*1024*1024, 0.020125); // actually 2, but 32bit
+  file_size_distn.normalize();
+
+  
+  for (int pggb = 1; pggb < 16; pggb++) {
+       cout << pggb;
+       for (int max = 1; max <= 1024; max *= 2) {
+         float avg, var, var2, var3;
+         off_t no;
+         max_object_size = max*1024;
+         testpgs(100, pggb, avg, var, no);
+         testpgs(100, pggb, avg, var2, no);
+         testpgs(100, pggb, avg, var3, no);
+         float dev = sqrt((var+var2+var3)/3.0);
+         cout << "\t" << no << "\t" << max << "\t" << dev;
+       }
+       cout << endl;
+  }
+
+
+
+
+}
diff --git a/trunk/ceph/crush.old/test/smallbucket.cc b/trunk/ceph/crush.old/test/smallbucket.cc
new file mode 100644 (file)
index 0000000..1dbc19b
--- /dev/null
@@ -0,0 +1,138 @@
+
+
+#include "../crush.h"
+using namespace crush;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+       b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       buckets[h].push_back(b);
+       return b;
+  } else {
+       // mixed
+       Bucket *b = new TreeBucket(h+1);
+       c.add_bucket(b);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+         n->set_parent(b->get_id());
+       }
+       buckets[h].push_back(b);
+       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
+  return b->get_id();
+}
+
+
+void place(Crush& c, Rule& rule, int numpg, int numrep, vector<int>& ocount)
+{
+  vector<int> v(numrep);
+  //map<int,int> ocount;
+
+  for (int x=1; x<=numpg; x++) {
+       
+       //cout << H(x) << "\t" << h(x) << endl;
+       c.do_rule(rule, x, v);
+       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
+       
+       bool bad = false;
+       for (int i=0; i<numrep; i++) {
+         //int d = b.choose_r(x, i, h);
+         //v[i] = d;
+         ocount[v[i]]++;
+         for (int j=i+1; j<numrep; j++) {
+               if (v[i] == v[j]) 
+                 bad = true;
+         }
+       }
+       if (bad)
+         cout << "bad set " << x << ": " << v << endl;
+       
+       //placement[x] = v;
+
+       //cout << v << "\t" << ocount << endl;
+  }
+  
+
+}
+
+
+int main()//float testmovement(int depth, int branching, int udisks)
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+  
+  vector<int> wid;
+  wid.push_back(10);
+  wid.push_back(2);
+
+  map< int, list<Bucket*> > buckets;
+  root = make_hierarchy(c, wid, buckets, ndisks);
+
+  // add small bucket
+  vector<int> disks;
+  for (int i=0; i<3; i++)
+       disks.push_back(ndisks++);
+  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
+  b->make_primes(h);
+  Bucket *o = buckets[1].back();
+  c.add_bucket(b);
+  //cout << " adding under " << o->get_id() << endl;
+  c.add_item(o->get_id(), b->get_id(), b->get_weight());
+  
+
+  // rule
+  int numrep = 6;
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+  //c.overload[10] = .1;
+
+  int pg_per = 10000;
+  int numpg = pg_per*ndisks/numrep;
+  
+  vector<int> ocount(ndisks);
+
+  c.print(cout, root);
+
+  place(c, rule, numpg, numrep, ocount);
+  
+  for (int i=0; i<ocount.size(); i++) {
+       cout << "disk " << i << " = " << ocount[i] << endl;
+  }
+
+  return 0;
+}
+
+
diff --git a/trunk/ceph/crush.old/test/speed_bucket.cc b/trunk/ceph/crush.old/test/speed_bucket.cc
new file mode 100644 (file)
index 0000000..973379f
--- /dev/null
@@ -0,0 +1,86 @@
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int numrep = 1;
+
+
+double go(int n, int bucket) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  Bucket *b;
+  vector<int> items;
+  if (bucket == 0) b = new UniformBucket(1,0,10,items);
+  if (bucket == 1) b = new TreeBucket(1);
+  if (bucket == 2) b = new ListBucket(1);
+  if (bucket == 3) b = new StrawBucket(1);
+
+  for (int d=0; d<n; d++)
+       b->add_item(ndisks++, 1);
+
+  //if (!bucket)       ((UniformBucket*)b)->make_primes(h);
+
+  root = c.add_bucket(b);
+
+  // rule
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+  int place = 1000000;
+
+
+  vector<int> v(numrep);
+  set<int> out;
+  map<int,float> overload;
+
+  utime_t start = g_clock.now();
+
+  for (int x=1; x <= place; x++)
+       c.do_rule(rule, x, v, out, overload);
+
+  utime_t end = g_clock.now();
+
+  end -= start;
+  double el = (double)end;
+
+  //cout << "\t" << ndisks;
+
+  return el;
+}
+
+
+int main() 
+{
+
+  for (int n=4; n<=50; n += 4) {
+       cout << n;
+       for (int b=0; b<4; b++) {
+         double el = go(n,b);
+         cout << "\t" << el;
+       }
+       cout << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/speed_depth.cc b/trunk/ceph/crush.old/test/speed_depth.cc
new file mode 100644 (file)
index 0000000..32275d1
--- /dev/null
@@ -0,0 +1,174 @@
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int uniform = 10;
+int branching = 10;
+int buckettype = 0;
+int numrep = 1;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b;
+       if (buckettype == 0)
+         b = new TreeBucket(h+1);
+       else if (buckettype == 1 || buckettype == 2)
+         b = new ListBucket(h+1);
+       else if (buckettype == 3)
+         b = new StrawBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+double go(int dep, int per) 
+{
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  if (1) {
+       wid.push_back(uniform);
+       for (int d=1; d<dep; d++)
+         wid.push_back(per);
+  }
+  if (0) {
+       if (dep == 0) 
+         wid.push_back(1000);
+       if (dep == 1) {
+         wid.push_back(1);
+         wid.push_back(1000);
+       }
+       if (dep == 2) {
+         wid.push_back(5);
+         wid.push_back(5);
+         wid.push_back(8);
+         wid.push_back(5);
+       }       
+  }
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  
+
+
+  // rule
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+  int place = 1000000;
+
+
+  vector<int> v(numrep);
+
+  utime_t start = g_clock.now();
+
+  set<int> out;
+  map<int,float> overload;
+
+  for (int x=1; x <= place; x++)
+       c.do_rule(rule, x, v, out, overload);
+
+  utime_t end = g_clock.now();
+
+  end -= start;
+  double el = (double)end;
+
+  //cout << "\t" << ndisks;
+
+  return el;
+}
+
+
+int main() 
+{
+  uniform = branching = 8;
+
+  cout << "// dep\tuniform\tbranch\tndisks" << endl;
+
+  for (int d=2; d<=5; d++) {
+       cout << d;// << "\t" << branching;
+       cout << "\t" << uniform;
+       cout << "\t" << branching;
+
+       int n = 1;
+       for (int i=0; i<d; i++)
+         n *= branching;
+       cout << "\t" << n;
+
+       numrep = 2;
+
+       // crush
+       for (buckettype = 0; buckettype <= 3; buckettype++) {
+         switch (buckettype) {
+         case 0: cout << "\ttree"; break;
+         case 1: cout << "\tlist"; break;
+         case 2: continue;
+         case 3: cout << "\tstraw"; break;
+         }
+
+         //for (numrep = 1; numrep <= 3; numrep++) {
+         //cout << "\t" << numrep;
+         
+         double el = go(d, branching);
+         cout << "\t" << el;
+       }
+
+       // rush
+
+       buckettype = 0;
+       cout << "\trush_T\t" << go(2, n/uniform);
+
+       buckettype = 1;
+       cout << "\trush_P\t" << go(2, n/uniform);
+
+       cout << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/speed_rush.cc b/trunk/ceph/crush.old/test/speed_rush.cc
new file mode 100644 (file)
index 0000000..93a5584
--- /dev/null
@@ -0,0 +1,145 @@
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int branching = 10;
+bool linear = false;
+int numrep = 1;
+
+Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
+{
+  if (h == 0) {
+       // uniform
+       Hash hash(123);
+       vector<int> disks;
+       for (int i=0; i<wid[h]; i++)
+         disks.push_back(ndisks++);
+       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
+       //b->make_primes(hash);  
+       c.add_bucket(b);
+       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
+       return b;
+  } else {
+       // mixed
+       Bucket *b;
+       if (linear)
+         b = new ListBucket(h+1);
+       else
+         b = new TreeBucket(h+1);
+       for (int i=0; i<wid[h]; i++) {
+         Bucket *n = make_bucket(c, wid, h-1, ndisks);
+         b->add_item(n->get_id(), n->get_weight());
+       }
+       c.add_bucket(b);
+       //cout << h << " mixedbucket with " << wid[h] << endl;
+       return b;
+  }
+}
+
+int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
+{
+  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
+  return b->get_id();
+}
+
+
+double go(int s) 
+{
+  int dep = 2;
+  Hash h(73232313);
+
+  // crush
+  Crush c;
+
+
+  // buckets
+  int root = -1;
+  int ndisks = 0;
+
+  vector<int> wid;
+  if (1) {
+       //for (int d=0; d<dep; d++)
+       wid.push_back(8);
+       wid.push_back(s/8);
+  }
+  if (0) {
+       if (dep == 0) 
+         wid.push_back(1000);
+       if (dep == 1) {
+         wid.push_back(1);
+         wid.push_back(1000);
+       }
+       if (dep == 2) {
+         wid.push_back(5);
+         wid.push_back(5);
+         wid.push_back(8);
+         wid.push_back(5);
+       }       
+  }
+
+  if (1) {
+       root = make_hierarchy(c, wid, ndisks);
+  }
+  
+
+
+  // rule
+  Rule rule;
+  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
+  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+
+
+  int place = 1000000;
+
+
+  vector<int> v(numrep);
+
+  utime_t start = g_clock.now();
+
+  for (int x=1; x <= place; x++)
+       c.do_rule(rule, x, v);
+
+  utime_t end = g_clock.now();
+
+  end -= start;
+  double el = (double)end;
+
+  cout << "\t" << ndisks;
+
+  return el;
+}
+
+
+int main() 
+{
+  branching = 8;
+
+  int d = 2;
+  numrep = 2;
+
+  for (int s = 64; s <= 32768; s *= 8) {
+       cout << "t";
+       linear = false;
+       double el = go(s, d);
+       cout << "\t" << el;
+
+       cout << "\tp";
+       linear = true;
+       el = go(s, d);
+       cout << "\t" << el;
+
+       cout << endl;
+  }
+}
diff --git a/trunk/ceph/crush.old/test/t.cc b/trunk/ceph/crush.old/test/t.cc
new file mode 100644 (file)
index 0000000..0785ef4
--- /dev/null
@@ -0,0 +1,25 @@
+
+#include "../../common/Clock.h"
+#include "../crush.h"
+using namespace crush;
+
+
+Clock g_clock;
+
+#include <math.h>
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+int branching = 10;
+bool linear = false;
+int numrep = 1;
+
+int main() {
+
+  Bucket *b = new UniformBucket(1, 0);
+  //b = new TreeBucket(1);
+}
+
diff --git a/trunk/ceph/crush.old/test/testbucket.cc b/trunk/ceph/crush.old/test/testbucket.cc
new file mode 100644 (file)
index 0000000..065721c
--- /dev/null
@@ -0,0 +1,61 @@
+
+
+#include "../Bucket.h"
+using namespace crush;
+
+#include <iostream>
+#include <vector>
+using namespace std;
+
+
+ostream& operator<<(ostream& out, vector<int>& v)
+{
+  out << "[";
+  for (int i=0; i<v.size(); i++) {
+       if (i) out << " ";
+       out << v[i];
+  }
+  out << "]";
+  return out;
+}
+
+
+int main() 
+{
+  Hash h(73);
+
+  int ndisks = 0;
+  int numrep = 3;
+
+  StrawBucket mb(1);
+  /*for (int i=0;i<10;i++)
+       mb.add_item(ndisks++, 10);
+  */
+  mb.add_item(ndisks++, 1);
+  mb.add_item(ndisks++, 1);
+  mb.add_item(ndisks++, 10);
+  mb.add_item(ndisks++, 10);
+  mb.add_item(ndisks++, 100);
+  mb.add_item(ndisks++, 1000);
+
+  vector<int> ocount(ndisks);
+
+  vector<int> v(numrep);
+  int nplace = 0;
+  for (int x=1; x<1000000; x++) {
+       //cout << H(x) << "\t" << h(x) << endl;
+       for (int i=0; i<numrep; i++) {
+         int d = mb.choose_r(x, i, h);
+         v[i] = d;
+         ocount[d]++;
+         nplace++;
+       }
+       //cout << v << "\t" << endl;//ocount << endl;
+  }
+
+  for (int i=0; i<ocount.size(); i++) {
+       float f = ocount[i] / (float)nplace;
+       cout << "disk " << i << " has " << ocount[i] << "  " << f << endl;
+  }
+
+}
diff --git a/trunk/ceph/crush.old/test/testnormal.cc b/trunk/ceph/crush.old/test/testnormal.cc
new file mode 100644 (file)
index 0000000..17c8cbf
--- /dev/null
@@ -0,0 +1,51 @@
+
+#include <vector>
+#include <iostream>
+using namespace std;
+
+
+void getdist(vector<int>& v, float& avg, float& var) 
+{
+  avg = 0.0;
+  for (int i=0; i<v.size(); i++)
+       avg += v[i];
+  avg /= v.size();
+  
+  var = 0.0;
+  for (int i=0; i<v.size(); i++)
+       var += (v[i] - avg) * (v[i] - avg);
+  var /= v.size();
+}
+
+int main() 
+{
+  int n = 50;
+  vector<int> a(n);
+  vector<int> b(n);
+
+  for (int i=0; i<n*n; i++)
+       a[rand()%n]++;
+
+  float aavg, avar;
+  getdist(a, aavg, avar);
+
+  for (int i=0; i<7*n*n; i++)
+       b[rand()%n]++;
+
+  float bavg, bvar;
+  getdist(b, bavg, bvar);
+
+  cout << "a avg " << aavg << " var " << avar << endl;
+  cout << "b avg " << bavg << " var " << bvar << endl;
+
+
+  vector<int> c(n);
+  for (int i=0; i<n; i++)
+       c[i] = a[i] * b[i];
+
+  float cavg, cvar;
+  getdist(c, cavg, cvar);
+
+  cout << "c avg " << cavg << " var " << cvar << endl;
+       
+}
diff --git a/trunk/ceph/crush/BinaryTree.h b/trunk/ceph/crush/BinaryTree.h
deleted file mode 100644 (file)
index 7573fc0..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-// -*- 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 __crush_BINARYTREE_H
-#define __crush_BINARYTREE_H
-
-#include <cassert>
-#include <iostream>
-#include <map>
-#include <vector>
-using std::map;
-using std::vector;
-
-#include "include/buffer.h"
-
-namespace crush {
-
-  class BinaryTree {
-  private:
-    // tree def
-    int             root_node;       // 0 for empty tree.
-    int             alloc;
-    vector<int>     node_nested;     // all existing nodes in this map
-    vector<float>   node_weight;     // and this one
-    vector<int>     node_complete;   // only nodes with all possible children
-
-  public:
-    BinaryTree() : root_node(0), alloc(0) {}
-    
-    void _encode(bufferlist& bl) {
-      bl.append((char*)&root_node, sizeof(root_node));
-      bl.append((char*)&alloc, sizeof(alloc));
-      ::_encode(node_nested, bl);
-      ::_encode(node_weight, bl);
-      ::_encode(node_complete, bl);
-    }
-    void _decode(bufferlist& bl, int& off) {
-      bl.copy(off, sizeof(root_node), (char*)&root_node);
-      off += sizeof(root_node);
-      bl.copy(off, sizeof(alloc), (char*)&alloc);
-      off += sizeof(alloc);
-      ::_decode(node_nested, bl, off);
-      ::_decode(node_weight, bl, off);
-      ::_decode(node_complete, bl, off);
-    }
-
-    // accessors
-    bool  empty() const { return root_node == 0; }
-    bool  exists(int n) const { return n < alloc && node_nested[n]; }
-    int   nested(int n) const { return exists(n) ? node_nested[n]:0; }
-    float weight(int n) const { return exists(n) ? node_weight[n]:0; }
-    bool  complete(int n) const { return exists(n) ? node_complete[n]:false; }
-
-    int   root() const { return root_node; }
-    
-    void   realloc(int n) {
-        /*
-        while (alloc <= n) {
-          node_nested.push_back(0);
-          node_weight.push_back(0);
-          node_complete.push_back(0);
-          alloc++;
-        }
-        */
-      if (alloc <= n) {
-        int add = n - alloc + 1;
-        node_nested.insert(node_nested.end(), add, 0);
-        node_weight.insert(node_weight.end(), add, 0);
-        node_complete.insert(node_complete.end(), add, 0);
-        alloc = n+1;
-      }
-    }
-
-    // tree navigation
-    bool terminal(int n) const { return n & 1; }  // odd nodes are leaves.
-    int height(int n) const {
-      assert(n);
-      int h = 0;
-      while ((n & 1) == 0) {
-        assert(n > 0);
-        h++; n = n >> 1;
-      }
-      return h;
-    }
-    int left(int n) const { 
-      int h = height(n);
-      //cout << "left of " << n << " is " << (n - (1 << h)) << std::endl;
-      return n - (1 << (h-1));
-    }
-    int right(int n) const {
-      int h = height(n);
-      //cout << "right of " << n << " is " << (n + (1 << h)) << std::endl;
-      return n + (1 << (h-1));
-    }
-    bool on_right(int n, int h = -1) const { 
-      if (h < 0) h = height(n);
-      return n & (1 << (h+1)); 
-    }
-    bool on_left(int n) const { return !on_right(n); }
-    int parent(int n) const {
-      int h = height(n);
-      if (on_right(n, h))
-        return n - (1<<h);
-      else
-        return n + (1<<h);
-    }
-    
-    // modifiers
-    void adjust_node_weight(int n, float w) {
-      assert(exists(n));
-      node_weight[n] += w;
-     
-      int p = n;
-      while (p != root_node) {
-        p = parent(p);
-        node_weight[p] += w;
-      }
-    }
-
-    void remove_node(int n) {
-      assert(exists(n));
-      
-      // erase node
-      node_nested[n] = 0;
-      node_weight[n] = 0;
-
-      // adjust parents (!complete, -weight)
-      int p = n;
-      while (p != root_node) {
-        p = parent(p);
-
-        node_complete[p] = 0;
-        node_weight[p] = weight(left(p)) + weight(right(p));
-        node_nested[p]--;
-
-        if (nested(p) == 0) {
-          node_weight[p] = 0;
-          node_nested[p] = 0;
-        }
-      }
-      
-      // hose root?
-      while (!terminal(root_node) &&
-             (nested(left(root_node)) == 0 ||
-             nested(right(root_node)) == 0)) {
-        // root now one child..
-        node_weight[root_node] = 0;
-        node_nested[root_node] = 0;
-        if (nested(left(root_node)) == 0)
-          root_node = right(root_node);
-        else 
-          root_node = left(root_node);
-      }
-
-      if (terminal(root_node) && 
-          nested(root_node) == 0) {
-        // empty!
-        node_weight[root_node] = 0;
-        node_nested[root_node] = 0;
-        root_node = 0;
-      }
-
-    }
-
-    int add_node_root(float w) {
-      return add_node(w, true);
-    }
-    
-    int add_node(float w, bool force_root=false) {
-      int n;
-      if (!root_node) {
-        // empty tree!
-        root_node = n = 1;
-      } else {
-        // existing tree.
-        // expand tree?
-        if (force_root || complete(root_node)) {
-          // add new root
-          int newroot = parent(root_node);
-          realloc(newroot);
-          node_weight[newroot] = node_weight[root_node];
-          node_nested[newroot] = nested(root_node);
-
-          // go right or left?
-          if (left(newroot) == root_node)
-            n = right(newroot);
-          else
-            n = left(newroot);
-          root_node = newroot;
-
-          // then go left until terminal
-          while (!terminal(n))
-            n = left(n);
-        }
-        else {
-          // tree isn't complete.
-          n = root_node;
-          while (!terminal(n)) {
-            if (!exists(left(n)) || !complete(left(n))) {
-              // left isn't complete
-              n = left(n);
-            } else {
-              assert(!exists(right(n)) || !complete(right(n)));
-              // right isn't complete
-              n = right(n);
-            }
-          }
-        }
-      }
-      
-      // create at n
-      //cout << "creating " << n << std::endl;
-      realloc(n);
-      node_weight[n] = w;
-      node_nested[n] = 1;
-      node_complete[n] = 1;
-
-      // ancestors: create, adjust weight, complete as appropriate
-      int p = n;
-      while (p != root_node) {
-        p = parent(p);
-        realloc(p);
-
-        // complete?
-        if (!complete(p) &&
-            complete(left(p)) && 
-            complete(right(p))) 
-          node_complete[p] = 1;
-        
-        // weight (and implicitly create)
-        node_weight[p] += w;
-        node_nested[p]++;
-      }
-
-      return n;
-
-    }
-    
-
-  };
-
-
-  // print it out
-  inline void print_binary_tree_node(ostream& out, const BinaryTree& tree, int n, int i) {
-    for (int t=i; t>0; t--) out << "  ";
-    if (tree.root() == n)
-      out << "root  ";
-    else {
-      if (tree.on_left(n))
-        out << "left  ";
-      else
-        out << "right ";
-    }
-    out << n << " : nested " << tree.nested(n) << "   weight " << tree.weight(n);
-    if (tree.complete(n)) out << "  complete";
-    out << std::endl;
-    if (!tree.terminal(n)) {
-      if (tree.exists(tree.left(n)))
-        print_binary_tree_node(out, tree, tree.left(n), i+2);
-      if (tree.exists(tree.right(n)))
-        print_binary_tree_node(out, tree, tree.right(n), i+2);
-    }
-  }
-  
-  inline ostream& operator<<(ostream& out, const BinaryTree& tree) {
-    if (tree.empty()) 
-      return out << "tree is empty";
-    print_binary_tree_node(out, tree, tree.root(), 0);    
-    return out;
-  }
-  
-}
-
-#endif
diff --git a/trunk/ceph/crush/Bucket.h b/trunk/ceph/crush/Bucket.h
deleted file mode 100644 (file)
index 81a2576..0000000
+++ /dev/null
@@ -1,632 +0,0 @@
-// -*- 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 __crush_BUCKET_H
-#define __crush_BUCKET_H
-
-#include "BinaryTree.h"
-#include "Hash.h"
-
-#include <list>
-#include <vector>
-#include <map>
-#include <set>
-using namespace std;
-
-#include <math.h>
-
-#include "include/buffer.h"
-
-namespace crush {
-
-
-  const int CRUSH_BUCKET_UNIFORM = 1;
-  const int CRUSH_BUCKET_TREE = 2;
-  const int CRUSH_BUCKET_LIST = 3;
-  const int CRUSH_BUCKET_STRAW = 4;
-
-  /** abstract bucket **/
-  class Bucket {
-  protected:
-    int         id;
-    int         parent;
-    int         type;
-    float       weight;
-
-  public:
-    Bucket(int _type,
-           float _weight) :
-      id(0), parent(0),
-      type(_type),
-      weight(_weight) { }
-
-    Bucket(bufferlist& bl, int& off) {
-      bl.copy(off, sizeof(id), (char*)&id);
-      off += sizeof(id);
-      bl.copy(off, sizeof(parent), (char*)&parent);
-      off += sizeof(parent);
-      bl.copy(off, sizeof(type), (char*)&type);
-      off += sizeof(type);
-      bl.copy(off, sizeof(weight), (char*)&weight);
-      off += sizeof(weight);
-    }
-
-    virtual ~Bucket() { }
-    
-    virtual const char *get_bucket_type() const = 0;
-    virtual bool is_uniform() const = 0;
-
-    int          get_id() const { return id; } 
-    int          get_type() const { return type; }
-    float        get_weight() const { return weight; }
-    int          get_parent() const { return parent; }
-    virtual int  get_size() const = 0;
-
-    void         set_id(int i) { id = i; }
-    void         set_parent(int p) { parent = p; }
-    void         set_weight(float w)  { weight = w; }
-
-    virtual void get_items(vector<int>& i) const = 0;
-    virtual float get_item_weight(int item) const = 0;
-    virtual void add_item(int item, float w, bool back=false) = 0;
-    virtual void adjust_item_weight(int item, float w) = 0;
-    virtual void set_item_weight(int item, float w) {
-      adjust_item_weight(item, w - get_item_weight(item));
-    }
-
-    virtual int choose_r(int x, int r, Hash& h) const = 0;
-
-    virtual void _encode(bufferlist& bl) = 0;
-  };
-
-
-
-
-  /** uniform bucket **/
-  class UniformBucket : public Bucket {    
-  protected:
-  public:
-    vector<int> items;
-    int    item_type;
-    float  item_weight;
-
-    // primes
-    vector<unsigned> primes;
-
-    int get_prime(int j) const {
-      return primes[ j % primes.size() ];
-    }
-    void make_primes() {
-      if (items.empty()) return;
-
-      //cout << "make_primes " << get_id() << " " << items.size() << endl;
-      Hash h(123+get_id());
-      primes.clear();
-
-      // start with odd number > num_items
-      unsigned x = items.size() + 1;             // this is the minimum!
-      x += h(items.size()) % (3*items.size());  // bump it up some
-      x |= 1;                               // make it odd
-
-      while (primes.size() < items.size()) {
-        unsigned j;
-        for (j=2; j*j<=x; j++) 
-          if (x % j == 0) break;
-        if (j*j > x) {
-          primes.push_back(x);
-          //cout << "prime " << x << endl;
-        }
-        x += 2;
-      }
-    }
-
-  public:
-    UniformBucket(int _type, int _item_type) :
-      Bucket(_type, 0),
-      item_type(_item_type) { }
-    UniformBucket(int _type, int _item_type,
-                  float _item_weight, vector<int>& _items) :
-      Bucket(_type, _item_weight*_items.size()),
-      item_type(_item_type),
-      item_weight(_item_weight) {
-      items = _items;
-      make_primes();
-    }
-
-    UniformBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
-      bl.copy(off, sizeof(item_type), (char*)&item_type);
-      off += sizeof(item_type);
-      bl.copy(off, sizeof(item_weight), (char*)&item_weight);
-      off += sizeof(item_weight);
-      ::_decode(items, bl, off);
-      make_primes();
-    }
-
-    void _encode(bufferlist& bl) {
-      char t = CRUSH_BUCKET_UNIFORM;
-      bl.append((char*)&t, sizeof(t));
-      bl.append((char*)&id, sizeof(id));
-      bl.append((char*)&parent, sizeof(parent));
-      bl.append((char*)&type, sizeof(type));
-      bl.append((char*)&weight, sizeof(weight));
-
-      bl.append((char*)&item_type, sizeof(item_type));
-      bl.append((char*)&item_weight, sizeof(item_weight));
-
-      ::_encode(items, bl);
-    }
-
-    const char *get_bucket_type() const { return "uniform"; }
-    bool is_uniform() const { return true; }
-
-    int get_size() const { return items.size(); }
-
-    // items
-    void get_items(vector<int>& i) const {
-      i = items;
-    }
-    int get_item_type() const { return item_type; }
-    float get_item_weight(int item) const { return item_weight; }
-
-    void add_item(int item, float w, bool back=false) {
-      if (items.empty())
-        item_weight = w;
-      items.push_back(item);
-      weight += item_weight;
-      make_primes();
-    }
-
-    void adjust_item_weight(int item, float w) {
-      assert(0);
-    }
-
-    int choose_r(int x, int r, Hash& hash) const {
-      //cout << "uniformbucket.choose_r(" << x << ", " << r << ")" << endl;
-      //if (r >= get_size()) cout << "warning: r " << r << " >= " << get_size() << " uniformbucket.size" << endl;
-      
-      unsigned v = hash(x, get_id());// % get_size();
-      unsigned p = get_prime( hash(get_id(), x) );  // choose a prime based on hash(x, get_id(), 2)
-      unsigned s = (x + v + (r+1)*p) % get_size();
-      return items[s];
-    }
-
-  };
-
-
-
-
-  
-  // list bucket.. RUSH_P sorta
-  
-  class ListBucket : public Bucket {
-  protected:
-    list<int>        items;
-    list<float>      item_weight;
-    list<float>      sum_weight;
-    
-  public:
-    ListBucket(int _type) : Bucket(_type, 0) { }
-
-    ListBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
-      ::_decode(items, bl, off);
-      ::_decode(item_weight, bl, off);
-      ::_decode(sum_weight, bl, off);
-    }
-
-    void _encode(bufferlist& bl) {
-      char t = CRUSH_BUCKET_LIST;
-      bl.append((char*)&t, sizeof(t));
-      bl.append((char*)&id, sizeof(id));
-      bl.append((char*)&parent, sizeof(parent));
-      bl.append((char*)&type, sizeof(type));
-      bl.append((char*)&weight, sizeof(weight));
-
-      ::_encode(items, bl);
-      ::_encode(item_weight, bl);
-      ::_encode(sum_weight, bl);
-    }
-
-    const char *get_bucket_type() const { return "list"; }
-    bool        is_uniform() const { return false; }
-
-    int get_size() const { return items.size(); }
-
-    void get_items(vector<int>& i) const {
-      for (list<int>::const_iterator it = items.begin();
-           it != items.end();
-           it++) 
-        i.push_back(*it);
-    }
-    float get_item_weight(int item) const {
-      list<int>::const_iterator i = items.begin();
-      list<float>::const_iterator w = item_weight.begin();
-      while (i != items.end()) {
-        if (*i == item) return *w;
-        i++; w++;
-      }
-      assert(0);
-      return 0;
-    }
-
-    void add_item(int item, float w, bool back=false) {
-      if (back) {
-        items.push_back(item);
-        item_weight.push_back(w);
-        sum_weight.clear();
-        float s = 0.0;
-        for (list<float>::reverse_iterator i = item_weight.rbegin();
-             i != item_weight.rend();
-             i++) {
-          s += *i;
-          sum_weight.push_front(s);
-        }
-        weight += w;
-        assert(weight == s);
-      } else {
-        items.push_front(item);
-        item_weight.push_front(w);
-        weight += w;
-        sum_weight.push_front(weight);
-      }
-    }
-
-    void adjust_item_weight(int item, float dw) {
-      // find it
-      list<int>::iterator p = items.begin();
-      list<float>::iterator pw = item_weight.begin();
-      list<float>::iterator ps = sum_weight.begin();
-
-      while (*p != item) {
-        *ps += dw;
-        p++; pw++; ps++;  // next!
-        assert(p != items.end());
-      }
-
-      assert(*p == item);
-      *pw += dw;
-      *ps += dw;
-    }
-
-    
-    int choose_r(int x, int r, Hash& h) const {
-      //cout << "linearbucket.choose_r(" << x << ", " << r << ")" << endl;
-
-      list<int>::const_iterator p = items.begin();
-      list<float>::const_iterator pw = item_weight.begin();
-      list<float>::const_iterator ps = sum_weight.begin();
-
-      while (p != items.end()) {
-        const int item = *p;
-        const float iw = *pw;
-        const float tw = *ps;
-        const float f = (float)(h(x, item, r, get_id()) % 10000) * tw / 10000.0;
-        //cout << "item " << item << "  iw = " << iw << "  tw = " << tw << "  f = " << f << endl;
-        if (f < iw) {
-          //cout << "linearbucket.choose_r(" << x << ", " << r << ") = " << item << endl;
-          return item;
-        }
-        p++; pw++; ps++;  // next!
-      }
-      assert(0);
-      return 0;
-    }    
-
-
-  };
-
-
-
-
-  // mixed bucket, based on RUSH_T type binary tree
-  
-  class TreeBucket : public Bucket {
-  protected:
-    //vector<float>  item_weight;
-
-    //  public:
-    BinaryTree     tree;
-    map<int,int>   node_item;     // node id -> item
-    vector<int>    node_item_vec; // fast version of above
-    map<int,int>   item_node;     // item -> node id
-    map<int,float> item_weight;
-
-  public:
-    TreeBucket(int _type) : Bucket(_type, 0) { }
-    
-    TreeBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
-      tree._decode(bl, off);
-      
-      ::_decode(node_item, bl, off);
-      ::_decode(node_item_vec, bl, off);
-      ::_decode(item_node, bl, off);
-      ::_decode(item_weight, bl, off);
-    }
-
-    void _encode(bufferlist& bl) {
-      char t = CRUSH_BUCKET_TREE;
-      bl.append((char*)&t, sizeof(t));
-      bl.append((char*)&id, sizeof(id));
-      bl.append((char*)&parent, sizeof(parent));
-      bl.append((char*)&type, sizeof(type));
-      bl.append((char*)&weight, sizeof(weight));
-
-      tree._encode(bl);
-
-      ::_encode(node_item, bl);
-      ::_encode(node_item_vec, bl);
-      ::_encode(item_node, bl);
-      ::_encode(item_weight, bl);
-    }
-
-    const char *get_bucket_type() const { return "tree"; }
-    bool        is_uniform() const { return false; }
-
-    int get_size() const { return node_item.size(); }
-
-    // items
-    void get_items(vector<int>& i) const {
-      for (map<int,int>::const_iterator it = node_item.begin();
-           it != node_item.end();
-           it++) 
-        i.push_back(it->second);    
-    }
-    float get_item_weight(int i) const { 
-      assert(item_weight.count(i));
-      return ((map<int,float>)item_weight)[i]; 
-    }
-
-
-    void add_item(int item, float w, bool back=false) {
-      item_weight[item] = w;
-      weight += w;
-
-      unsigned n = tree.add_node(w);
-      node_item[n] = item;
-      item_node[item] = n;
-
-      while (node_item_vec.size() <= n) 
-        node_item_vec.push_back(0);
-      node_item_vec[n] = item;
-    }
-    
-    void adjust_item_weight(int item, float dw) {
-      // adjust my weight
-      weight += dw;
-      item_weight[item] += dw;
-
-      // adjust tree weights
-      tree.adjust_node_weight(item_node[item], dw);
-    }
-    
-    int choose_r(int x, int r, Hash& h) const {
-      //cout << "mixedbucket.choose_r(" << x << ", " << r << ")" << endl;
-      int n = tree.root();
-      while (!tree.terminal(n)) {
-        // pick a point in [0,w)
-        float w = tree.weight(n);
-        float f = (float)(h(x, n, r, get_id()) % 10000) * w / 10000.0;
-
-        // left or right?
-        int l = tree.left(n);
-        if (tree.exists(l) && 
-            f < tree.weight(l))
-          n = l;
-        else
-          n = tree.right(n);
-      }
-      //assert(node_item.count(n));
-      //return ((map<int,int>)node_item)[n];
-      return node_item_vec[n];
-    }
-  };
-
-
-
-
-
-  // straw bucket.. new thing!
-  
-  class StrawBucket : public Bucket {
-  protected:
-    map<int, float>  item_weight;
-    map<int, float>  item_straw;
-
-    list<int>   _items;
-    list<float> _straws;
-
-  public:
-    StrawBucket(int _type) : Bucket(_type, 0) { }
-
-    StrawBucket(bufferlist& bl, int& off) : Bucket(bl, off) {
-      ::_decode(item_weight, bl, off);
-      calc_straws();
-    }
-
-    void _encode(bufferlist& bl) {
-      char t = CRUSH_BUCKET_TREE;
-      bl.append((char*)&t, sizeof(t));
-      bl.append((char*)&id, sizeof(id));
-      bl.append((char*)&parent, sizeof(parent));
-      bl.append((char*)&type, sizeof(type));
-      bl.append((char*)&weight, sizeof(weight));
-
-      ::_encode(item_weight, bl);
-    }
-
-    const char *get_bucket_type() const { return "straw"; }
-    bool is_uniform() const { return false; }
-
-    int get_size() const { return item_weight.size(); }
-
-
-    // items
-    void get_items(vector<int>& i) const {
-      for (map<int,float>::const_iterator it = item_weight.begin();
-           it != item_weight.end();
-           it++) 
-        i.push_back(it->first);
-    }
-    float get_item_weight(int item) const {
-      assert(item_weight.count(item));
-      return ((map<int,float>)item_weight)[item];
-    }
-
-    void add_item(int item, float w, bool back=false) {
-      item_weight[item] = w;
-      weight += w;
-      calc_straws();
-    }
-
-    void adjust_item_weight(int item, float dw) {
-      //cout << "adjust " << item << " " << dw << endl;
-      weight += dw;
-      item_weight[item] += dw;
-      calc_straws();
-    }
-    
-    
-    /* calculate straw lengths.
-       this is kind of ugly.  not sure if there's a closed form way to calculate this or not!    
-     */
-    void calc_straws() {
-      //cout << get_id() << ": calc_straws ============" << endl;
-
-      item_straw.clear();
-      _items.clear();
-      _straws.clear();
-
-      // reverse sort by weight; skip zero weight items
-      map<float, set<int> > reverse;
-      for (map<int, float>::iterator p = item_weight.begin();
-           p != item_weight.end();
-           p++) {
-        //cout << get_id() << ":" << p->first << " " << p->second << endl;
-        if (p->second > 0) {
-          //p->second /= minw;
-          reverse[p->second].insert(p->first);
-        }
-      }
-
-      /* 1:2:7 
-         item_straw[0] = 1.0;
-         item_straw[1] = item_straw[0]*sqrt(1.0/.6);
-         item_straw[2] = item_straw[1]*2.0;
-      */
-
-      // work from low to high weights
-      float straw = 1.0;
-      float numleft = item_weight.size();
-      float wbelow = 0.0;
-      float lastw = 0.0;
-      
-      map<float, set<int> >::iterator next = reverse.begin();
-      //while (next != reverse.end()) {
-      while (1) {
-        //cout << "hi " << next->first << endl;
-        map<float, set<int> >::iterator cur = next;
-        
-        // set straw length for this set
-        for (set<int>::iterator s = cur->second.begin();
-             s != cur->second.end();
-             s++) {
-          item_straw[*s] = straw;
-          //cout << "straw " << *s << " w " << item_weight[*s] << " -> " << straw << endl;
-          _items.push_back(*s);
-          _straws.push_back(straw);
-        }
-        
-        next++;
-        if (next == reverse.end()) break;
-        
-        wbelow += (cur->first-lastw) * numleft;
-        //cout << "wbelow " << wbelow << endl;
-        
-        numleft -= 1.0 * (float)cur->second.size();
-        //cout << "numleft now " << numleft << endl;
-        
-        float wnext = numleft * (next->first - cur->first);
-        //cout << "wnext " << wnext << endl;
-        
-        float pbelow = wbelow / (wbelow+wnext);
-        //cout << "pbelow " << pbelow << endl;
-        
-        straw *= pow((double)(1.0/pbelow), (double)1.0/numleft);
-        
-        lastw = cur->first;
-      }
-      //cout << "============" << endl;
-    }
-
-    int choose_r(int x, int r, Hash& h) const {
-      //cout << "strawbucket.choose_r(" << x << ", " << r << ")" << endl;
-
-      float high_draw = -1;
-      int high = 0;
-
-      list<int>::const_iterator pi = _items.begin();
-      list<float>::const_iterator ps = _straws.begin();
-      while (pi != _items.end()) {
-        const int item = *pi;
-        const float rnd = (float)(h(x, item, r) % 1000000) / 1000000.0;
-        const float straw = *ps * rnd;
-        
-        if (high_draw < 0 ||
-            straw > high_draw) {
-          high = *pi;
-          high_draw = straw;
-        }
-
-        pi++;
-        ps++;
-      }
-      return high;
-    }    
-  };
-
-
-
-
-
-  inline Bucket* decode_bucket(bufferlist& bl, int& off) {
-    char t;
-    bl.copy(off, sizeof(t), (char*)&t);
-    off += sizeof(t);
-
-    switch (t) {
-    case CRUSH_BUCKET_UNIFORM:
-      return new UniformBucket(bl, off);
-    case CRUSH_BUCKET_LIST:
-      return new ListBucket(bl, off);
-    case CRUSH_BUCKET_TREE:
-      return new TreeBucket(bl, off);
-    case CRUSH_BUCKET_STRAW:
-      return new StrawBucket(bl, off);
-    default:
-      assert(0);
-    }
-    return 0;
-  }
-
-
-
-}
-
-
-
-
-
-
-
-
-#endif
diff --git a/trunk/ceph/crush/CrushWrapper.h b/trunk/ceph/crush/CrushWrapper.h
new file mode 100644 (file)
index 0000000..5222902
--- /dev/null
@@ -0,0 +1,227 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+
+#ifndef __CRUSH_WRAPPER_H
+#define __CRUSH_WRAPPER_H
+
+#include "crush.h"
+#include "hash.h"
+#include "mapper.h"
+#include "builder.h"
+
+#include "include/encodable.h"
+
+#include <map>
+#include <set>
+
+class CrushWrapper {
+public:
+  struct crush_map *map;
+  
+  CrushWrapper() : map(0) {}
+  ~CrushWrapper() {
+    if (map) crush_destroy(map);
+  }  
+
+  void create() {
+    if (map) crush_destroy(map);
+    map = crush_create();
+  }
+  void finalize() {
+    assert(map);
+    crush_finalize(map);
+  }
+
+  void update_offload_map(std::set<int32_t>& out_osds,
+                         std::map<int32_t,float>& overload_osds) {
+    for (int i=0; i<map->max_devices; i++) {
+      if (out_osds.count(i))
+       map->device_offload[i] = 0x10000;
+      else if (overload_osds.count(i)) 
+       map->device_offload[i] = (int)(0x10000 * overload_osds[i]); // FIXME: reverse?
+      else
+       map->device_offload[i] = 0;  // normal.
+    }
+  }
+
+  void do_rule(int rule, int x, vector<int>& out, int maxout, int forcefeed) {
+    int rawout[maxout];
+    
+    int numrep = crush_do_rule(map, rule, x, rawout, maxout, forcefeed);
+
+    out.resize(numrep);
+    for (int i=0; i<numrep; i++)
+      out[i] = rawout[i];
+  }
+
+  void _encode(bufferlist &bl) {
+    ::_encode_simple(map->max_buckets, bl);
+    ::_encode_simple(map->max_rules, bl);
+    ::_encode_simple(map->max_devices, bl);
+
+    // simple arrays
+    bl.append((char*)map->device_offload, sizeof(map->device_offload[0]) * map->max_devices);
+
+    // buckets
+    for (unsigned i=0; i<map->max_buckets; i++) {
+      __u32 type = 0;
+      if (map->buckets[i]) type = map->buckets[i]->bucket_type;
+      ::_encode_simple(type, bl);
+      if (!type) continue;
+
+      ::_encode_simple(map->buckets[i]->id, bl);
+      ::_encode_simple(map->buckets[i]->type, bl);
+      ::_encode_simple(map->buckets[i]->bucket_type, bl);
+      ::_encode_simple(map->buckets[i]->weight, bl);
+      ::_encode_simple(map->buckets[i]->size, bl);
+      for (unsigned j=0; j<map->buckets[i]->size; j++)
+       ::_encode_simple(map->buckets[i]->items[j], bl);
+      
+      switch (map->buckets[i]->type) {
+      case CRUSH_BUCKET_UNIFORM:
+       for (unsigned j=0; j<map->buckets[i]->size; j++)
+         ::_encode_simple(((crush_bucket_uniform*)map->buckets[i])->primes[j], bl);
+       ::_encode_simple(((crush_bucket_uniform*)map->buckets[i])->item_weight, bl);
+       break;
+
+      case CRUSH_BUCKET_LIST:
+       for (unsigned j=0; j<map->buckets[i]->size; j++) {
+         ::_encode_simple(((crush_bucket_list*)map->buckets[i])->item_weights[j], bl);
+         ::_encode_simple(((crush_bucket_list*)map->buckets[i])->sum_weights[j], bl);
+       }
+       break;
+
+      case CRUSH_BUCKET_TREE:
+       for (unsigned j=0; j<map->buckets[i]->size; j++) 
+         ::_encode_simple(((crush_bucket_tree*)map->buckets[i])->node_weights[j], bl);
+       break;
+
+      case CRUSH_BUCKET_STRAW:
+       for (unsigned j=0; j<map->buckets[i]->size; j++) 
+         ::_encode_simple(((crush_bucket_straw*)map->buckets[i])->straws[j], bl);
+       break;
+      }
+    }
+
+    // rules
+    for (unsigned i=0; i<map->max_rules; i++) {
+      __u32 yes = map->rules[i] ? 1:0;
+      ::_encode_simple(yes, bl);
+      if (!yes) continue;
+
+      ::_encode_simple(map->rules[i]->len, bl);
+      for (unsigned j=0; j<map->rules[i]->len; j++)
+       ::_encode_simple(map->rules[i]->steps[j], bl);
+    }
+  }
+
+  void _decode(bufferlist::iterator &blp) {
+    create();
+    ::_decode_simple(map->max_buckets, blp);
+    ::_decode_simple(map->max_rules, blp);
+    ::_decode_simple(map->max_devices, blp);
+
+    map->device_offload = (__u32*)malloc(sizeof(map->device_offload[0])*map->max_devices);
+    blp.copy(sizeof(map->device_offload[0])*map->max_devices, (char*)map->device_offload);
+    
+    // buckets
+    map->buckets = (crush_bucket**)malloc(sizeof(crush_bucket*)*map->max_buckets);
+    for (unsigned i=0; i<map->max_buckets; i++) {
+      __u32 type;
+      ::_decode_simple(type, blp);
+      if (!type) {
+       map->buckets[i] = 0;
+       continue;
+      }
+
+      int size = 0;
+      switch (type) {
+      case CRUSH_BUCKET_UNIFORM:
+       size = sizeof(crush_bucket_uniform);
+       break;
+      case CRUSH_BUCKET_LIST:
+       size = sizeof(crush_bucket_list);
+       break;
+      case CRUSH_BUCKET_TREE:
+       size = sizeof(crush_bucket_tree);
+       break;
+      case CRUSH_BUCKET_STRAW:
+       size = sizeof(crush_bucket_straw);
+       break;
+      default:
+       assert(0);
+      }
+      map->buckets[i] = (crush_bucket*)malloc(size);
+      memset(map->buckets[i], 0, size);
+      
+      ::_decode_simple(map->buckets[i]->id, blp);
+      ::_decode_simple(map->buckets[i]->type, blp);
+      ::_decode_simple(map->buckets[i]->bucket_type, blp);
+      ::_decode_simple(map->buckets[i]->weight, blp);
+      ::_decode_simple(map->buckets[i]->size, blp);
+
+      map->buckets[i]->items = (__s32*)malloc(sizeof(__s32)*map->buckets[i]->size);
+      for (unsigned j=0; j<map->buckets[i]->size; j++)
+       ::_decode_simple(map->buckets[i]->items[j], blp);
+
+      switch (map->buckets[i]->type) {
+      case CRUSH_BUCKET_UNIFORM:
+       ((crush_bucket_uniform*)map->buckets[i])->primes = 
+         (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+       for (unsigned j=0; j<map->buckets[i]->size; j++)
+         ::_decode_simple(((crush_bucket_uniform*)map->buckets[i])->primes[j], blp);
+       ::_decode_simple(((crush_bucket_uniform*)map->buckets[i])->item_weight, blp);
+       break;
+
+      case CRUSH_BUCKET_LIST:
+       ((crush_bucket_list*)map->buckets[i])->item_weights = 
+         (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+       ((crush_bucket_list*)map->buckets[i])->sum_weights = 
+         (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+
+       for (unsigned j=0; j<map->buckets[i]->size; j++) {
+         ::_decode_simple(((crush_bucket_list*)map->buckets[i])->item_weights[j], blp);
+         ::_decode_simple(((crush_bucket_list*)map->buckets[i])->sum_weights[j], blp);
+       }
+       break;
+
+      case CRUSH_BUCKET_TREE:
+       ((crush_bucket_tree*)map->buckets[i])->node_weights = 
+         (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+       for (unsigned j=0; j<map->buckets[i]->size; j++) 
+         ::_decode_simple(((crush_bucket_tree*)map->buckets[i])->node_weights[j], blp);
+       break;
+
+      case CRUSH_BUCKET_STRAW:
+       ((crush_bucket_straw*)map->buckets[i])->straws = 
+         (__u32*)malloc(map->buckets[i]->size * sizeof(__u32));
+       for (unsigned j=0; j<map->buckets[i]->size; j++) 
+         ::_decode_simple(((crush_bucket_straw*)map->buckets[i])->straws[j], blp);
+       break;
+      }
+    }
+
+    // rules
+    map->rules = (crush_rule**)malloc(sizeof(crush_rule*)*map->max_rules);
+    for (unsigned i=0; i<map->max_rules; i++) {
+      __u32 yes;
+      ::_decode_simple(yes, blp);
+      if (!yes) {
+       map->rules[i] = 0;
+       continue;
+      }
+
+      map->rules[i] = (crush_rule*)malloc(sizeof(crush_rule));
+      memset(map->rules[i], 0, sizeof(crush_rule));
+
+      ::_decode_simple(map->rules[i]->len, blp);
+      map->rules[i]->steps = (crush_rule_step*)malloc(sizeof(crush_rule_step) * map->rules[i]->len);
+      for (unsigned j=0; j<map->rules[i]->len; j++)
+       ::_decode_simple(map->rules[i]->steps[j], blp);
+    }
+
+    finalize();
+  }
+};
+
+#endif
diff --git a/trunk/ceph/crush/Hash.h b/trunk/ceph/crush/Hash.h
deleted file mode 100644 (file)
index 2f0d9e4..0000000
+++ /dev/null
@@ -1,301 +0,0 @@
-// -*- 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.
- * 
- */
-
-
-// Robert Jenkins' function for mixing 32-bit values
-// http://burtleburtle.net/bob/hash/evahash.html
-// a, b = random bits, c = input and output
-#define hashmix(a,b,c) \
-        a=a-b;  a=a-c;  a=a^(c>>13); \
-        b=b-c;  b=b-a;  b=b^(a<<8);  \
-        c=c-a;  c=c-b;  c=c^(b>>13); \
-        a=a-b;  a=a-c;  a=a^(c>>12); \
-        b=b-c;  b=b-a;  b=b^(a<<16); \
-        c=c-a;  c=c-b;  c=c^(b>>5);  \
-        a=a-b;  a=a-c;  a=a^(c>>3); \
-        b=b-c;  b=b-a;  b=b^(a<<10); \
-        c=c-a;  c=c-b;  c=c^(b>>15); 
-
-namespace crush {
-  
-  class Hash {
-    int seed;
-
-  public:
-    int get_seed() { return seed; }
-    void set_seed(int s) { seed = s; }
-
-    Hash(int s) {
-      unsigned int hash = 1315423911;
-      int x = 231232;
-      int y = 1232;
-      hashmix(s, x, hash);
-      hashmix(y, s, hash);
-      seed = s;
-    }
-
-    inline int operator()(int a) {
-      unsigned int hash = seed ^ a;
-      int b = a;
-      int x = 231232;
-      int y = 1232;
-      hashmix(b, x, hash);
-      hashmix(y, a, hash);
-      return (hash & 0x7FFFFFFF);
-    }
-
-    inline int operator()(int a, int b) {
-      unsigned int hash = seed ^ a ^ b;
-      int x = 231232;
-      int y = 1232;
-      hashmix(a, b, hash);
-      hashmix(x, a, hash);
-      hashmix(b, y, hash);
-      return (hash & 0x7FFFFFFF);
-    }
-
-    inline int operator()(int a, int b, int c) {
-      unsigned int hash = seed ^ a ^ b ^ c;
-      int x = 231232;
-      int y = 1232;
-      hashmix(a, b, hash);
-      hashmix(c, x, hash);
-      hashmix(y, a, hash);
-      hashmix(b, x, hash);
-      hashmix(y, c, hash);
-      return (hash & 0x7FFFFFFF);
-    }
-
-    inline int operator()(int a, int b, int c, int d) {
-      unsigned int hash = seed ^a ^ b ^ c ^ d;
-      int x = 231232;
-      int y = 1232;
-      hashmix(a, b, hash);
-      hashmix(c, d, hash);
-      hashmix(a, x, hash);
-      hashmix(y, b, hash);
-      hashmix(c, x, hash);
-      hashmix(y, d, hash);
-      return (hash & 0x7FFFFFFF);
-    }
-
-    inline int operator()(int a, int b, int c, int d, int e) {
-      unsigned int hash = seed ^ a ^ b ^ c ^ d ^ e;
-      int x = 231232;
-      int y = 1232;
-      hashmix(a, b, hash);
-      hashmix(c, d, hash);
-      hashmix(e, x, hash);
-      hashmix(y, a, hash);
-      hashmix(b, x, hash);
-      hashmix(y, c, hash);
-      hashmix(d, x, hash);
-      hashmix(y, e, hash);
-      return (hash & 0x7FFFFFFF);
-    }
-  };
-
-}
-
-
-
-#if 0
-
-
-      //return myhash(a) ^ seed;
-      return myhash(a, seed);
-    }
-    int operator()(int a, int b) {
-      //return myhash( myhash(a) ^ myhash(b) ^ seed );
-      return myhash(a, b, seed);
-    }
-    int operator()(int a, int b, int c) {
-      //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ seed );
-      return myhash(a, b, c, seed);
-    }
-    int operator()(int a, int b, int c, int d) {
-      //return myhash( myhash(a ^ seed) ^ myhash(b ^ seed) ^ myhash(c ^ seed) ^ myhash(d ^ seed) ^ seed );
-      return myhash(a, b, c, d, seed);
-    }
-
-      // ethan's rush hash?
-      if (0) 
-        return (n ^ 0xdead1234) * (884811920 * 3  + 1);
-
-      if (1) {
-
-        // before
-        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
-        hashmix(a, b, hash);
-        n = n >> 8;
-        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
-        hashmix(a, b, hash);
-        n = n >> 8;
-        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
-        hashmix(a, b, hash);
-        n = n >> 8;
-        hash ^= ((hash << 5) + (n&255) + (hash >> 2));
-        hashmix(a, b, hash);
-        n = n >> 8;
-
-        //return hash;
-        return (hash & 0x7FFFFFFF);
-      }
-
-      // JS
-      //  a little better than RS
-      //  + jenkin's mixing thing (which sucks on its own but helps tons here)
-      //  best so far
-      if (1) {
-        unsigned int hash = 1315423911;
-        int a = 231232;
-        int b = 1232;
-        
-        for(unsigned int i = 0; i < 4; i++)
-          {
-            hash ^= ((hash << 5) + (n&255) + (hash >> 2));
-            hashmix(a, b, hash);
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-      
-      // Robert jenkins' 96 bit mix
-      //  sucks
-      if (0) {
-        int c = n;
-        int a = 12378912;
-        int b = 2982827;
-        a=a-b;  a=a-c;  a=a^(c>>13); 
-        b=b-c;  b=b-a;  b=b^(a<<8);  
-        c=c-a;  c=c-b;  c=c^(b>>13); 
-        a=a-b;  a=a-c;  a=a^(c>>12); 
-        b=b-c;  b=b-a;  b=b^(a<<16); 
-        c=c-a;  c=c-b;  c=c^(b>>5);  
-        a=a-b;  a=a-c;  a=a^(c>>3); 
-        b=b-c;  b=b-a;  b=b^(a<<10); 
-        c=c-a;  c=c-b;  c=c^(b>>15); 
-        return c;
-      }
-      // robert jenkins 32-bit
-      //  sucks
-      if (0) {
-        n += (n << 12);
-        n ^= (n >> 22);
-        n += (n << 4);
-        n ^= (n >> 9);
-        n += (n << 10);
-        n ^= (n >> 2);
-        n += (n << 7);
-        n ^= (n >> 12);
-        return n;
-      }
-
-      // djb2
-      if (0) {
-        unsigned int hash = 5381;
-        for (int i=0; i<4; i++) {
-          hash = ((hash << 5) + hash) + ((n&255) ^ 123);
-          n = n >> 8;
-        }
-        return hash;
-      }
-
-
-      // SDBM
-      if (1) {
-        unsigned int hash = 0;
-        
-        for(unsigned int i = 0; i < 4; i++)
-          {
-            hash = (n&255) + (hash << 6) + (hash << 16) - hash;
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-      // PJW
-      //  horrid
-      if (0) {
-        unsigned int BitsInUnsignedInt = (unsigned int)(sizeof(unsigned int) * 8);
-        unsigned int ThreeQuarters     = (unsigned int)((BitsInUnsignedInt  * 3) / 4);
-        unsigned int OneEighth         = (unsigned int)(BitsInUnsignedInt / 8);
-        unsigned int HighBits          = (unsigned int)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
-        unsigned int hash              = 0;
-        unsigned int test              = 0;
-        
-        for(unsigned int i = 0; i < 4; i++)
-          {
-            hash = (hash << OneEighth) + (n&255);
-            
-            if((test = hash & HighBits)  != 0)
-              {
-                hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
-              }
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-      // RS Hash function, from Robert Sedgwicks Algorithms in C book, w/ some changes.
-      if (0) {
-        unsigned int b    = 378551;
-        unsigned int a    = 63689;
-        unsigned int hash = 0;
-        
-        for(unsigned int i=0; i<4; i++)
-          {
-            hash = hash * a + (n&0xff);
-            a    = a * b;
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-      // DJB
-      //  worse than rs
-      if (0) {
-        unsigned int hash = 5381;
-        
-        for(unsigned int i = 0; i < 4; i++)
-          {
-            hash = ((hash << 5) + hash) + (n&255);
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-      // AP
-      //  even worse
-      if (1) {
-        unsigned int hash = 0;
-        
-        for(unsigned int i = 0; i < 4; i++)
-          {
-            hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ (n&255) ^ (hash >> 3)) :
-              (~((hash << 11) ^ (n&255) ^ (hash >> 5)));
-            n = n >> 8;
-          }
-        
-        return (hash & 0x7FFFFFFF);
-      }
-
-
-#endif
diff --git a/trunk/ceph/crush/Makefile b/trunk/ceph/crush/Makefile
new file mode 100644 (file)
index 0000000..72d1b67
--- /dev/null
@@ -0,0 +1,30 @@
+
+CC = gcc
+CFLAGS = -Wall
+CFLAGS += -g
+CFLAGS += -O3
+LD = ld
+RM = rm
+
+all: depend libcrush.o test
+
+clean:
+       rm -f *.o libcrush.o
+
+%.o: %.c
+       ${CC} ${CFLAGS} -c $< -o $@
+
+libcrush.o: builder.o crush.o mapper.o
+       $(LD) -i -o $@ $^
+
+test: test.c libcrush.o
+       $(CC) ${CFLAGS} -lm $^ -o $@
+
+.depend:
+       touch .depend
+
+depend:
+       $(RM) .depend
+       makedepend -f- -- $(CFLAGS) -- *.c > .depend 2>/dev/null
+
+include .depend
diff --git a/trunk/ceph/crush/buckets.c b/trunk/ceph/crush/buckets.c
new file mode 100644 (file)
index 0000000..72441d1
--- /dev/null
@@ -0,0 +1,6 @@
+
+#include "crush.h"
+#include "hash.h"
+
+int 
+
diff --git a/trunk/ceph/crush/builder.c b/trunk/ceph/crush/builder.c
new file mode 100644 (file)
index 0000000..a430dbd
--- /dev/null
@@ -0,0 +1,375 @@
+
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "builder.h"
+#include "hash.h"
+
+struct crush_map *crush_create()
+{
+       struct crush_map *m;
+       m = malloc(sizeof(*m));
+       memset(m, 0, sizeof(*m));
+       return m;
+}
+
+/*
+ * finalize should be called _after_ all buckets are added to the map.
+ */
+void crush_finalize(struct crush_map *map)
+{
+       int b, i, c;
+       
+       /* calc max_devices */
+       for (b=0; b<map->max_buckets; b++) {
+               if (map->buckets[b] == 0) continue;
+               for (i=0; i<map->buckets[b]->size; i++) 
+                       if (map->buckets[b]->items[i] >= map->max_devices)
+                               map->max_devices = map->buckets[b]->items[i] + 1;
+       }
+       
+       /* allocate arrays */
+       map->device_parents = malloc(sizeof(map->device_parents[0]) * map->max_devices);
+       memset(map->device_parents, 0, sizeof(map->device_parents[0]) * map->max_devices);
+       map->bucket_parents = malloc(sizeof(map->bucket_parents[0]) * map->max_buckets);
+       memset(map->bucket_parents, 0, sizeof(map->bucket_parents[0]) * map->max_buckets);
+       
+       /* build parent maps */
+       for (b=0; b<map->max_buckets; b++) {
+               if (map->buckets[b] == 0) continue;
+               for (i=0; i<map->buckets[b]->size; i++) {
+                       c = map->buckets[b]->items[i];
+                       BUG_ON(c >= map->max_devices);
+                       if (c >= 0)
+                               map->device_parents[c] = map->buckets[b]->id;
+                       else
+                               map->bucket_parents[-1-c] = map->buckets[b]->id;
+               }
+       }
+
+       /* new device offload map? */
+       if (!map->device_offload) {
+               map->device_offload = malloc(sizeof(map->device_offload[0]) * map->max_devices);
+               memset(map->device_offload, 0, sizeof(map->device_offload[0]) * map->max_devices);
+       }
+}
+
+
+
+
+
+/** rules **/
+
+int crush_add_rule(struct crush_map *map,
+                  int ruleno, 
+                  struct crush_rule *rule)
+{
+       int oldsize;
+
+       if (ruleno < 0) {
+               for (ruleno=0; ruleno < map->max_rules; ruleno++)
+                       if (map->rules[ruleno] == 0) break;
+       }
+       if (ruleno >= map->max_rules) {
+               /* expand array */
+               oldsize = map->max_rules;
+               map->max_rules = ruleno+1;
+               map->rules = realloc(map->rules, map->max_rules * sizeof(map->rules[0]));
+               memset(map->rules + oldsize, 0, (map->max_rules-oldsize) * sizeof(map->rules[0]));
+       }
+       
+       /* add it */
+       map->rules[ruleno] = rule;
+       return ruleno;
+}
+
+struct crush_rule *crush_make_rule()
+{
+       struct crush_rule *rule;
+       
+       rule = malloc(sizeof(struct crush_rule));
+       memset(rule, 0, sizeof(*rule));
+       return rule;
+}
+
+void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2)
+{
+       rule->len++;
+       if (rule->steps)
+               rule->steps = realloc(rule->steps, sizeof(rule->steps[0])*rule->len);
+       else
+               rule->steps = malloc(sizeof(rule->steps[0])*rule->len);
+       rule->steps[rule->len-1].op = op;
+       rule->steps[rule->len-1].arg1 = arg1;
+       rule->steps[rule->len-1].arg2 = arg2;
+}
+
+
+/** buckets **/
+
+int crush_add_bucket(struct crush_map *map,
+                    struct crush_bucket *bucket)
+{
+       int id;
+       int oldsize;
+       
+       /* find a bucket id */
+       for (id=0; id < map->max_buckets; id++)
+               if (map->buckets[id] == 0) break;
+       if (id == map->max_buckets) {
+               /* expand array */
+               oldsize = map->max_buckets;
+               if (map->max_buckets)
+                       map->max_buckets *= 2;
+               else
+                       map->max_buckets = 8;
+               map->buckets = realloc(map->buckets, map->max_buckets * sizeof(map->buckets[0]));
+               memset(map->buckets + oldsize, 0, (map->max_buckets-oldsize) * sizeof(map->buckets[0]));
+       }
+       
+       /* add it */
+       bucket->id = -1 - id;
+       map->buckets[id] = bucket;
+       return -1 - id;
+}
+
+
+/* uniform bucket */
+
+struct crush_bucket_uniform *
+crush_make_uniform_bucket(int type, int size,
+                         int *items,
+                         int item_weight)
+{
+       int i, j, x;
+       struct crush_bucket_uniform *bucket;
+       
+       bucket = malloc(sizeof(*bucket));
+       memset(bucket, 0, sizeof(*bucket));
+       bucket->h.bucket_type = CRUSH_BUCKET_UNIFORM;
+       bucket->h.type = type;
+       bucket->h.size = size;
+       bucket->h.weight = size * item_weight;
+       
+       bucket->item_weight = item_weight;
+       
+       bucket->h.items = malloc(sizeof(__u32)*size);
+       for (i=0; i<size; i++)
+               bucket->h.items[i] = items[i];
+       
+       /* generate some primes */
+       bucket->primes = malloc(sizeof(__u32)*size);
+
+       x = size + 1;
+       x += crush_hash32(size) % (3*size);  /* make it big */
+       x |= 1;                              /* and odd */
+       
+       i=0;
+       while (i < size) {
+               for (j=2; j*j <= x; j++) 
+                       if (x % j == 0) break;
+               if (j*j > x) 
+                       bucket->primes[i++] = x;
+               x += 2;
+       }
+
+       return bucket;
+}
+
+
+/* list bucket */
+
+struct crush_bucket_list*
+crush_make_list_bucket(int type, int size,
+                      int *items,
+                      int *weights)
+{
+       int i;
+       int w;
+       struct crush_bucket_list *bucket;
+
+       bucket = malloc(sizeof(*bucket));
+       memset(bucket, 0, sizeof(*bucket));
+       bucket->h.bucket_type = CRUSH_BUCKET_LIST;
+       bucket->h.type = type;
+       bucket->h.size = size;
+       
+       bucket->h.items = malloc(sizeof(__u32)*size);
+       bucket->item_weights = malloc(sizeof(__u32)*size);
+       bucket->sum_weights = malloc(sizeof(__u32)*size);
+       w = 0;
+       for (i=size-1; i>=0; i--) {
+               bucket->h.items[i] = items[i];
+               bucket->item_weights[i] = weights[i];
+               w += weights[i];
+               bucket->sum_weights[i] = w;
+               /*printf("%d item %d weight %d sum %d\n",
+                 i, items[i], weights[i], bucket->sum_weights[i]);*/
+       }
+       
+       bucket->h.weight = w;
+
+       return bucket;
+}
+
+
+/* tree bucket */
+
+static int height(int n) {
+       int h = 0;
+       while ((n & 1) == 0) {
+               h++; 
+               n = n >> 1;
+       }
+       return h;
+}
+static int on_right(int n, int h) { 
+       return n & (1 << (h+1)); 
+}
+static int parent(int n) 
+{
+       int h = height(n);
+       if (on_right(n, h))
+               return n - (1<<h);
+       else
+               return n + (1<<h);
+}
+
+struct crush_bucket_tree*
+crush_make_tree_bucket(int type, int size,
+                      int *items,    /* in leaf order */
+                      int *weights)
+{
+       struct crush_bucket_tree *bucket;
+       int depth;
+       int node;
+       int t, i, j;
+       
+       bucket = malloc(sizeof(*bucket));
+       memset(bucket, 0, sizeof(*bucket));
+       bucket->h.bucket_type = CRUSH_BUCKET_TREE;
+       bucket->h.type = type;
+       bucket->h.size = size;
+
+       /* calc tree depth */
+       depth = 1;
+       t = size - 1;
+       while (t) {
+               t = t >> 1;
+               depth++;
+       }
+       bucket->h.size = 1 << depth;
+
+       bucket->h.items = malloc(sizeof(__u32)*bucket->h.size);
+       bucket->node_weights = malloc(sizeof(__u32)*bucket->h.size);
+
+       memset(bucket->h.items, 0, sizeof(__u32)*bucket->h.size);
+       memset(bucket->node_weights, 0, sizeof(__u32)*bucket->h.size);
+       
+       for (i=0; i<size; i++) {
+               node = ((i+1) << 1)-1;
+               bucket->h.items[node] = items[i];
+               bucket->node_weights[node] = weights[i];
+               bucket->h.weight += weights[i];
+               for (j=1; j<depth; j++) {
+                       node = parent(node);
+                       bucket->node_weights[node] += weights[i];
+               }
+       }
+       BUG_ON(bucket->node_weights[bucket->h.size/2] != bucket->h.weight);
+
+       return bucket;
+}
+
+
+/* straw bucket */
+
+struct crush_bucket_straw *
+crush_make_straw_bucket(int type, 
+                       int size,
+                       int *items,
+                       int *weights)
+{
+       struct crush_bucket_straw *bucket;
+       int *reverse;
+       int i, j, k;
+       
+       double straw, wbelow, lastw, wnext, pbelow;
+       int numleft;
+       
+       bucket = malloc(sizeof(*bucket));
+       memset(bucket, 0, sizeof(*bucket));
+       bucket->h.bucket_type = CRUSH_BUCKET_STRAW;
+       bucket->h.type = type;
+       bucket->h.size = size;
+       
+       bucket->h.items = malloc(sizeof(__u32)*size);
+       bucket->straws = malloc(sizeof(__u32)*size);
+       
+       bucket->h.weight = 0;
+       for (i=0; i<size; i++) {
+               bucket->h.items[i] = items[i];
+               bucket->h.weight += weights[i];
+       }
+       
+       /* reverse sort by weight (simple insertion sort) */
+       reverse = malloc(sizeof(int) * size);
+       reverse[0] = 0;
+       for (i=1; i<size; i++) {
+               for (j=0; j<i; j++) {
+                       if (weights[i] < weights[reverse[j]]) {
+                               /* insert here */
+                               for (k=i; k>j; k--)
+                                       reverse[k] = reverse[k-1];
+                               reverse[j] = i;
+                               break;
+                       }
+               }
+               if (j == i)
+                       reverse[i] = i;
+       }
+       
+       numleft = size;
+       straw = 1.0;
+       wbelow = 0;
+       lastw = 0;
+       
+       i=0;
+       while (i < size) {
+               /* set this item's straw */
+               bucket->straws[reverse[i]] = straw * 0x10000;
+               /*printf("item %d at %d weight %d straw %d (%lf)\n", 
+                      items[reverse[i]],
+                      reverse[i], weights[reverse[i]], bucket->straws[reverse[i]], straw);*/
+               i++;
+               if (i == size) break;
+               
+               /* same weight as previous? */
+               if (weights[reverse[i]] == weights[reverse[i-1]]) {
+                       /*printf("same as previous\n");*/
+                       continue;
+               }
+               
+               /* adjust straw for next guy */
+               wbelow += ((double)weights[reverse[i-1]] - lastw) * numleft;
+               for (j=i; j<size; j++)
+                       if (weights[reverse[j]] == weights[reverse[i]])
+                               numleft--;
+                       else
+                               break;
+               wnext = numleft * (weights[reverse[i]] - weights[reverse[i-1]]);
+               pbelow = wbelow / (wbelow + wnext);
+               /*printf("wbelow %lf  wnext %lf  pbelow %lf\n", wbelow, wnext, pbelow);*/
+               
+               straw *= pow((double)1.0 / pbelow, (double)1.0 / (double)numleft);
+               
+               lastw = weights[reverse[i-1]];
+       }
+       
+       free(reverse);
+       
+       return bucket;
+}
+
diff --git a/trunk/ceph/crush/builder.h b/trunk/ceph/crush/builder.h
new file mode 100644 (file)
index 0000000..a324e3f
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef _CRUSH_BUILDER_H
+#define _CRUSH_BUILDER_H
+
+#include "crush.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern struct crush_map *crush_create();
+extern void crush_finalize(struct crush_map *map);
+
+/* rules */
+extern struct crush_rule *crush_make_rule();
+extern int crush_add_rule(struct crush_map *map,
+                         int ruleno,
+                         struct crush_rule *rule);
+extern void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2);
+
+/* buckets */
+extern int crush_add_bucket(struct crush_map *map,
+                           struct crush_bucket *bucket);
+
+struct crush_bucket_uniform *
+crush_make_uniform_bucket(int type, int size,
+                         int *items,
+                         int item_weight);
+struct crush_bucket_list*
+crush_make_list_bucket(int type, int size,
+                      int *items,
+                      int *weights);
+struct crush_bucket_tree*
+crush_make_tree_bucket(int type, int size,
+                      int *items,    /* in leaf order */
+                      int *weights);
+struct crush_bucket_straw *
+crush_make_straw_bucket(int type, int size,
+                       int *items,
+                       int *weights);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/trunk/ceph/crush/crush.c b/trunk/ceph/crush/crush.c
new file mode 100644 (file)
index 0000000..fd27414
--- /dev/null
@@ -0,0 +1,81 @@
+
+#ifdef __KERNEL__
+# define free(x) kfree(x)
+#else
+# include <stdlib.h>
+#endif
+
+#include "crush.h"
+
+void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
+{
+       free(b->primes);
+       free(b->h.items);
+       free(b);
+}
+
+void crush_destroy_bucket_list(struct crush_bucket_list *b)
+{
+       free(b->item_weights);
+       free(b->sum_weights);
+       free(b->h.items);
+       free(b);
+}
+
+void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
+{
+       free(b->node_weights);
+       free(b);
+}
+
+void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
+{
+       free(b->straws);
+       free(b->h.items);
+       free(b);
+}
+
+
+/* 
+ * deallocate
+ */
+void crush_destroy(struct crush_map *map)
+{
+       int b;
+       
+       /* buckets */
+       for (b=0; b<map->max_buckets; b++) {
+               if (map->buckets[b] == 0) continue;
+               switch (map->buckets[b]->type) {
+               case CRUSH_BUCKET_UNIFORM:
+                       crush_destroy_bucket_uniform((struct crush_bucket_uniform*)map->buckets[b]);
+                       break;
+               case CRUSH_BUCKET_LIST:
+                       crush_destroy_bucket_list((struct crush_bucket_list*)map->buckets[b]);
+                       break;
+               case CRUSH_BUCKET_TREE:
+                       crush_destroy_bucket_tree((struct crush_bucket_tree*)map->buckets[b]);
+                       break;
+               case CRUSH_BUCKET_STRAW:
+                       crush_destroy_bucket_straw((struct crush_bucket_straw*)map->buckets[b]);
+                       break;
+               }
+       }
+       free(map->buckets);
+       
+       /* rules */
+       for (b=0; b<map->max_rules; b++) {
+               if (map->rules[b] == 0) continue;
+               if (map->rules[b]->steps)
+                       free(map->rules[b]->steps);
+               free(map->rules[b]);
+       }
+       free(map->rules);
+       
+       free(map->bucket_parents);
+       free(map->device_parents);
+       free(map->device_offload);
+       free(map);
+}
+
+
index 376e7d9b3fc86d4775d1125c831ea955b4deb5b6..5cf6cff498f131d3f60cacf1d0d18e6e2813e9c2 100644 (file)
-// -*- 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 _CRUSH_CRUSH_H
+#define _CRUSH_CRUSH_H
 
-#ifndef __crush_CRUSH_H
-#define __crush_CRUSH_H
-
-#include <iostream>
-#include <list>
-#include <vector>
-#include <set>
-#include <map>
-using std::set;
-using std::map;
-using std::vector;
-using std::list;
-#include <ext/hash_map>
-#include <ext/hash_set>
-using namespace __gnu_cxx;
-
-
-#include "Bucket.h"
-
-#include "include/buffer.h"
-
-
-namespace crush {
-
-
-  // *** RULES ***
-
-  class RuleStep {
-  public:
-    int         cmd;
-    vector<int> args;
-
-    RuleStep(int c) : cmd(c) {}
-    RuleStep(int c, int a) : cmd(c) {
-      args.push_back(a);
-    }
-    RuleStep(int c, int a, int b) : cmd(c) {
-      args.push_back(a);
-      args.push_back(b);
-    }
-    RuleStep(int o, int a, int b, int c) : cmd(o) {
-      args.push_back(a);
-      args.push_back(b);
-      args.push_back(c);
-    }
-
-    void _encode(bufferlist& bl) {
-      bl.append((char*)&cmd, sizeof(cmd));
-      ::_encode(args, bl);
-    }
-    void _decode(bufferlist& bl, int& off) {
-      bl.copy(off, sizeof(cmd), (char*)&cmd);
-      off += sizeof(cmd);
-      ::_decode(args, bl, off);
-    }
-  };
-
-
-  // Rule operations
-  const int CRUSH_RULE_TAKE = 0;
-  const int CRUSH_RULE_CHOOSE = 1;         // first n by default
-  const int CRUSH_RULE_CHOOSE_FIRSTN = 1;
-  const int CRUSH_RULE_CHOOSE_INDEP = 2;
-  const int CRUSH_RULE_EMIT = 3;
-
-  class Rule {
-  public:
-    vector< RuleStep > steps;
-
-    void _encode(bufferlist& bl) {
-      int n = steps.size();
-      bl.append((char*)&n, sizeof(n));
-      for (int i=0; i<n; i++)
-        steps[i]._encode(bl);
-    }
-    void _decode(bufferlist& bl, int& off) {
-      steps.clear();
-      int n;
-      bl.copy(off, sizeof(n), (char*)&n);
-      off += sizeof(n);
-      for (int i=0; i<n; i++) {
-        steps.push_back(RuleStep(0));
-        steps[i]._decode(bl, off);
-      }
-    }
-  };
-
-
-
-
-  // *** CRUSH ***
-
-  class Crush {
-  protected:
-    map<int, Bucket*>  buckets;
-    int bucketno;
-    Hash h;
-
-    hash_map<int, int> parent_map;  // what bucket each leaf/bucket lives in
-
-  public:
-    map<int, Rule>     rules;
-
-    //map<int,int> collisions;
-    //map<int,int> bumps;    
-
-    void _encode(bufferlist& bl) {
-      // buckets
-      int n = buckets.size();
-      bl.append((char*)&n, sizeof(n));
-      for (map<int, Bucket*>::const_iterator it = buckets.begin();
-           it != buckets.end();
-           it++) {
-        bl.append((char*)&it->first, sizeof(it->first));
-        it->second->_encode(bl);
-      }
-      bl.append((char*)&bucketno, sizeof(bucketno));
-
-      // hash
-      int s = h.get_seed();
-      bl.append((char*)&s, sizeof(s));
-
-      //::_encode(out, bl);
-      //::_encode(overload, bl);
-      
-      // rules
-      n = rules.size();
-      bl.append((char*)&n, sizeof(n));
-      for(map<int, Rule>::iterator it = rules.begin();
-          it != rules.end();
-          it++) {
-        bl.append((char*)&it->first, sizeof(it->first));
-        it->second._encode(bl);
-      }
-        
-    }
-
-    void _decode(bufferlist& bl, int& off) {
-      int n;
-      bl.copy(off, sizeof(n), (char*)&n);
-      off += sizeof(n);
-      for (int i=0; i<n; i++) {
-        int bid;
-        bl.copy(off, sizeof(bid), (char*)&bid);
-        off += sizeof(bid);
-        Bucket *b = decode_bucket(bl, off);
-        buckets[bid] = b;
-      }
-      bl.copy(off, sizeof(bucketno), (char*)&bucketno);
-      off += sizeof(bucketno);
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-      int s;
-      bl.copy(off, sizeof(s), (char*)&s);
-      off += sizeof(s);
-      h.set_seed(s);
+#include <linux/types.h>  /* just for int types */
 
-      //::_decode(out, bl, off);
-      //::_decode(overload, bl, off);
+#ifndef BUG_ON
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+#endif
 
-      // rules
-      bl.copy(off, sizeof(n), (char*)&n);
-      off += sizeof(n);
-      for (int i=0; i<n; i++) {
-        int r;
-        bl.copy(off, sizeof(r), (char*)&r);
-        off += sizeof(r);
-        rules[r]._decode(bl,off);
-      }
-      
-      // index
-      build_parent_map();
-    }
 
-    void build_parent_map() {
-      parent_map.clear();
-      
-      // index every bucket
-      for (map<int, Bucket*>::iterator bp = buckets.begin();
-          bp != buckets.end();
-          ++bp) {
-       // index bucket items
-       vector<int> items;
-       bp->second->get_items(items);
-       for (vector<int>::iterator ip = items.begin();
-            ip != items.end();
-            ++ip)
-         parent_map[*ip] = bp->first;
-      }
-    }
-    
+/*** RULES ***/
+enum {
+       CRUSH_RULE_TAKE,
+       CRUSH_RULE_CHOOSE_FIRSTN,
+       CRUSH_RULE_CHOOSE_INDEP,
+       CRUSH_RULE_EMIT
+};
 
+#define CRUSH_MAX_DEPTH 10
+#define CRUSH_MAX_SET   10
 
-  public:
-    Crush(int seed=123) : bucketno(-1), h(seed) {}
-    ~Crush() {
-      // hose buckets
-      for (map<int, Bucket*>::iterator it = buckets.begin();
-           it != buckets.end();
-           it++) {
-        delete it->second;
-      }
-    }
+struct crush_rule_step {
+       __u32 op;
+       __s32 arg1;
+       __s32 arg2;
+};
 
-    int print(ostream& out, int root, int indent=0) {
-      for (int i=0; i<indent; i++) out << " ";
-      Bucket *b = buckets[root];
-      assert(b);
-      out << b->get_weight() << "\t" << b->get_id() << "\t";
-      for (int i=0; i<indent; i++) out << " ";
-      out << b->get_bucket_type() << ": ";
+struct crush_rule {
+       __u32 len;
+       struct crush_rule_step *steps;
+};
 
-      vector<int> items;
-      b->get_items(items);
 
-      if (buckets.count(items[0])) {
-        out << std::endl;
-        for (unsigned i=0; i<items.size(); i++)
-          print(out, items[i], indent+1);
-      } else {
-        out << "[";
-        for (unsigned i=0; i<items.size(); i++) {
-          if (i) out << " ";
-          out << items[i];
-        }
-        out << "]";
-      }
-      return 0;
-    }
 
+/*** BUCKETS ***/
 
-    int add_bucket( Bucket *b ) {
-      int n = bucketno;
-      bucketno--;
-      b->set_id(n);
-      buckets[n] = b;
-      return n;
-    }
+enum {
+       CRUSH_BUCKET_UNIFORM = 1,
+       CRUSH_BUCKET_LIST = 2,
+       CRUSH_BUCKET_TREE = 3,
+       CRUSH_BUCKET_STRAW = 4
+};
 
-    void add_item(int parent, int item, float w, bool back=false) {
-      // add item
-      assert(!buckets[parent]->is_uniform());
-      Bucket *p = buckets[parent];
-      
-      p->add_item(item, w, back);
+struct crush_bucket {
+       __s32 id;        /* this'll be negative */
+       __u16 type;
+       __u16 bucket_type;
+       __u32 weight;    /* 16-bit fixed point */
+       __u32 size;      /* num items */
+       __s32 *items;
+};
 
-      // set item's parent
-      Bucket *n = buckets[item];
-      if (n)
-        n->set_parent(parent);
+struct crush_bucket_uniform {
+       struct crush_bucket h;
+       __u32 *primes;
+       __u32 item_weight;  /* 16-bit fixed point */
+};
 
-      // update weights
-      while (buckets.count(p->get_parent())) {
-        int child = p->get_id();
-        p = buckets[p->get_parent()];
-        p->adjust_item_weight(child, w);
-      }
-    }
+struct crush_bucket_list {
+       struct crush_bucket h;
+       __u32 *item_weights;  /* 16-bit fixed point */
+       __u32 *sum_weights;   /* 16-bit fixed point.  element i is sum of weights 0..i, inclusive */
+};
 
+struct crush_bucket_tree {
+       struct crush_bucket h;  /* note: h.size is tree size, not number of actual items */
+       __u32 *node_weights;
+};
 
-    /*
-    this is a hack, fix me!  weights should be consistent throughout hierarchy!
-    
-     */
-    void set_bucket_weight(int item, float w) {
-      Bucket *b = buckets[item];
-      float adj = w - b->get_weight();
+struct crush_bucket_straw {
+       struct crush_bucket h;
+       __u32 *straws;  /* 16-bit fixed point */
+};
 
-      while (buckets.count(b->get_parent())) {
-        Bucket *p = buckets[b->get_parent()];
-        p->adjust_item_weight(b->get_id(), adj);
-        b = p;
-      }
-    }
 
 
-    /*
-     * choose numrep distinct items of type type
-     */
-    void choose(int x,
-                int numrep,
-                int type,
-                Bucket *inbucket,
-                vector<int>& outvec,
-                bool firstn,
-                set<int>& outset, map<int,float>& overloadmap,
-               bool forcefeed=false,
-               int forcefeedval=-1) {
-      int off = outvec.size();
+/*** CRUSH ***/
 
-      // for each replica
-      for (int rep=0; rep<numrep; rep++) {
-        int outv = -1;                   // my result
-        
-       // forcefeed?
-       if (forcefeed) {
-         forcefeed = false;
-         outvec.push_back(forcefeedval);
-         continue;
-       }
+struct crush_map {
+       struct crush_bucket **buckets;
+       struct crush_rule **rules;
        
-        // keep trying until we get a non-out, non-colliding item
-        int ftotal = 0;
-        bool skip_rep = false;
+       /* parent pointers */
+       __u32 *bucket_parents;
+       __u32 *device_parents;
        
-        while (1) {
-          // start with the input bucket
-          Bucket *in = inbucket;
-          
-          // choose through intervening buckets
-          int flocal = 0;
-          bool retry_rep = false;
-
-          while (1) {
-            // r may be twiddled to (try to) avoid past collisions
-            int r = rep;
-            if (in->is_uniform()) {
-              // uniform bucket; be careful!
-              if (firstn || numrep >= in->get_size()) {
-                // uniform bucket is too small; just walk thru elements
-                r += ftotal;                    // r' = r + f_total (first n)
-              } else {
-                // make sure numrep is not a multple of bucket size
-                int add = numrep*flocal;        // r' = r + n*f_local
-                if (in->get_size() % numrep == 0) {
-                  add += add/in->get_size();         // shift seq once per pass through the bucket
-                }
-                r += add;
-              }
-            } else {
-              // mixed bucket; just make a distinct-ish r sequence
-              if (firstn)
-                r += ftotal;          // r' = r + f_total
-              else
-                r += numrep * flocal; // r' = r + n*f_local
-            }
-            
-            // choose
-            outv = in->choose_r(x, r, h);                     
-            
-            // did we get the type we want?
-            int itemtype = 0;          // 0 is terminal type
-            Bucket *newin = 0;         // remember bucket we hit
-            if (in->is_uniform()) {
-              itemtype = ((UniformBucket*)in)->get_item_type();
-            } else {
-              if (buckets.count(outv)) {  // another bucket
-                newin = buckets[outv];
-                itemtype = newin->get_type();
-              } 
-            }
-            if (itemtype == type) { // this is what we want!
-              // collision?
-              bool collide = false;
-              for (int prep=0; prep<rep; prep++) {
-                if (outvec[off+prep] == outv) {
-                  collide = true;
-                  break;
-                }
-              }
-
-              // ok choice?
-              bool bad = false;
-              if (type == 0 && outset.count(outv)) 
-                bad = true;
-              if (overloadmap.count(outv)) {
-                float f = (float)(h(x, outv) % 1000) / 1000.0;
-                if (f > overloadmap[outv])
-                  bad = true;
-              }
-
-              if (collide || bad) {
-                ftotal++;
-                flocal++;
-                
-                if (collide && flocal < 3) 
-                  continue;  // try locally a few times!
-                
-                if (ftotal >= 10) {
-                  // ok fine, just ignore dup.  FIXME.
-                  skip_rep = true;
-                  break;
-                }
-                
-                retry_rep = true;
-              }
-
-              break;  // ok then!
-            }
-
-            // next
-            in = newin;
-          }
-          
-          if (retry_rep) continue;  // try again
-
-          break;
-        }
-
-        // skip this rep? (e.g. too many collisions, we give up)
-        if (skip_rep) continue; 
-
-        // output this value
-        outvec.push_back(outv);
-      } // for rep
-
-      // double check!
-      if (0) {
-        for (unsigned i=1; i<outvec.size(); i++) 
-          for (unsigned j=0; j<i; j++)
-            assert(outvec[i] != outvec[j]);
-      }
-    }
-
-
-    void do_rule(Rule& rule, int x, vector<int>& result,
-                 set<int>& outset, map<int,float>& overloadmap,
-                int forcefeed=-1) {
-      //int numresult = 0;
-      result.clear();
-
-      // determine hierarchical context for forcefeed (if any)
-      list<int> force_stack;
-      if (forcefeed >= 0 && parent_map.count(forcefeed)) {
-       int t = forcefeed;
-       while (1) {
-         force_stack.push_front(t);
-         //cout << "push " << t << " onto force_stack" << std::endl;
-         if (parent_map.count(t) == 0) break;  // reached root, presumably.
-         //cout << " " << t << " parent is " << parent_map[t] << std::endl;
-         t = parent_map[t];
-       }
-      }
-      
-      // working vector
-      vector<int> w;   // working variable
-      
-      // go through each statement
-      for (vector<RuleStep>::iterator pc = rule.steps.begin();
-           pc != rule.steps.end();
-           pc++) {
-        // move input?
-        
-        // do it
-        switch (pc->cmd) {
-        case CRUSH_RULE_TAKE:
-          {    
-           const int arg = pc->args[0];
-           //cout << "take " << arg << std::endl;            
-           
-           if (!force_stack.empty()) {
-             assert(force_stack.front() == arg);
-             force_stack.pop_front();
-           }
-           
-           w.clear();
-           w.push_back(arg);
-          }
-          break;
-          
-        case CRUSH_RULE_CHOOSE_FIRSTN:
-        case CRUSH_RULE_CHOOSE_INDEP:
-          {
-            const bool firstn = pc->cmd == CRUSH_RULE_CHOOSE_FIRSTN;
-            const int numrep = pc->args[0];
-            const int type = pc->args[1];
-
-            //cout << "choose " << numrep << " of type " << type << std::endl;
-
-            assert(!w.empty());
-
-            // reset output
-            vector<int> out;
-
-            // forcefeeding?
-           bool forcing = false;
-           int forceval = -1;
-           if (!force_stack.empty()) {
-             forceval = force_stack.front();
-             force_stack.pop_front();
-             //cout << "priming out with " << forceval << std::endl;
-             forcing = true;
-           } else if (forcefeed >= 0 && type == 0) {
-             //cout << "forcing context-less " << forcefeed << std::endl;
-             forceval = forcefeed;
-             forcefeed = -1;
-             forcing = true;
-           }
-           
-            // do each row independently
-            for (vector<int>::iterator i = w.begin();
-                 i != w.end();
-                 i++) {
-              assert(buckets.count(*i));
-              Bucket *b = buckets[*i];
-             choose(x, numrep, type, b, out, firstn,
-                    outset, overloadmap,
-                    forcing,
-                    forceval);
-             forcing = false;  // only once
-            } // for inrow
-            
-            // put back into w
-            w.swap(out);
-            out.clear();
-          }
-          break;
-
-        case CRUSH_RULE_EMIT:
-          {
-            for (unsigned i=0; i<w.size(); i++)
-              result.push_back(w[i]);
-            //result[numresult++] = w[i];
-            w.clear();
-          }
-          break;
-
-        default:
-          assert(0);
-        }
-      }
+       /* offload
+        * size max_devices, values 0...0xffff
+        *        0 == normal
+        *  0x10000 == 100% offload (i.e. failed)
+        */
+       __u32 *device_offload;   
+       
+       __u32 max_buckets;
+       __u32 max_rules;
+       __s32 max_devices;
+};
 
-    }
 
+/* common destructors */
+extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *);
+extern void crush_destroy_bucket_list(struct crush_bucket_list *);
+extern void crush_destroy_bucket_tree(struct crush_bucket_tree *);
+extern void crush_destroy_bucket_straw(struct crush_bucket_straw *);
+extern void crush_destroy(struct crush_map *map);
 
-  };
 
+#ifdef __cplusplus
 }
+#endif
 
 #endif
diff --git a/trunk/ceph/crush/hash.h b/trunk/ceph/crush/hash.h
new file mode 100644 (file)
index 0000000..1ff4cca
--- /dev/null
@@ -0,0 +1,80 @@
+#ifndef _CRUSH_HASH_H
+#define _CRUSH_HASH_H
+
+// Robert Jenkins' function for mixing 32-bit values
+// http://burtleburtle.net/bob/hash/evahash.html
+// a, b = random bits, c = input and output
+#define hashmix(a,b,c) \
+        a=a-b;  a=a-c;  a=a^(c>>13); \
+        b=b-c;  b=b-a;  b=b^(a<<8);  \
+        c=c-a;  c=c-b;  c=c^(b>>13); \
+        a=a-b;  a=a-c;  a=a^(c>>12); \
+        b=b-c;  b=b-a;  b=b^(a<<16); \
+        c=c-a;  c=c-b;  c=c^(b>>5);  \
+        a=a-b;  a=a-c;  a=a^(c>>3); \
+        b=b-c;  b=b-a;  b=b^(a<<10); \
+        c=c-a;  c=c-b;  c=c^(b>>15); 
+
+#define crush_hash_seed 1315423911
+
+static __inline__ unsigned crush_hash32(unsigned a) {
+       unsigned hash = crush_hash_seed ^ a;
+       unsigned b = a;
+       unsigned x = 231232;
+       unsigned y = 1232;
+       hashmix(b, x, hash);
+       hashmix(y, a, hash);
+       return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_2(unsigned a, unsigned b) {
+       unsigned hash = crush_hash_seed ^ a ^ b;
+       unsigned x = 231232;
+       unsigned y = 1232;
+       hashmix(a, b, hash);
+       hashmix(x, a, hash);
+       hashmix(b, y, hash);
+       return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_3(unsigned a, unsigned b, unsigned c) {
+       unsigned int hash = crush_hash_seed ^ a ^ b ^ c;
+       unsigned x = 231232;
+       unsigned y = 1232;
+       hashmix(a, b, hash);
+       hashmix(c, x, hash);
+       hashmix(y, a, hash);
+       hashmix(b, x, hash);
+       hashmix(y, c, hash);
+       return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_4(unsigned a, unsigned b, unsigned c, unsigned d) {
+       unsigned int hash = crush_hash_seed ^a ^ b ^ c ^ d;
+       unsigned x = 231232;
+       unsigned y = 1232;
+       hashmix(a, b, hash);
+       hashmix(c, d, hash);
+       hashmix(a, x, hash);
+       hashmix(y, b, hash);
+       hashmix(c, x, hash);
+       hashmix(y, d, hash);
+       return (hash & 0xFFFFFFFF);
+}
+
+static __inline__ unsigned crush_hash32_5(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e) {
+       unsigned int hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
+       unsigned x = 231232;
+       unsigned y = 1232;
+       hashmix(a, b, hash);
+       hashmix(c, d, hash);
+       hashmix(e, x, hash);
+       hashmix(y, a, hash);
+       hashmix(b, x, hash);
+       hashmix(y, c, hash);
+       hashmix(d, x, hash);
+       hashmix(y, e, hash);
+       return (hash & 0xFFFFFFFF);
+}
+
+#endif
diff --git a/trunk/ceph/crush/mapper.c b/trunk/ceph/crush/mapper.c
new file mode 100644 (file)
index 0000000..e0a71f8
--- /dev/null
@@ -0,0 +1,351 @@
+
+#include "crush.h"
+#include "hash.h"
+
+#include <string.h>
+#include <stdio.h>
+
+/** bucket choose methods **/
+
+/* uniform */
+
+static int 
+crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r)
+{
+       unsigned o, p, s;
+       o = crush_hash32_2(x, bucket->h.id) & 0xffff;
+       p = bucket->primes[crush_hash32_2(bucket->h.id, x) % bucket->h.size];
+       s = (x + o + (r+1)*p) % bucket->h.size;
+       /*printf("%d %d %d %d\n", x, o, r, p);*/
+       return bucket->h.items[s];
+}
+
+
+/* list */
+
+static int 
+crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r)
+{
+       int i;
+       __u64 w;
+       
+       for (i=0; i<bucket->h.size; i++) {
+               w = crush_hash32_4(x, bucket->h.items[i], r, bucket->h.id);
+               w &= 0xffff;
+               /*printf("%d item %d weight %d sum_weight %d r %lld", 
+                 i, bucket->h.items[i], bucket->item_weights[i], bucket->sum_weights[i], w);*/
+               w *= bucket->sum_weights[i];
+               w = w >> 16;
+               /*printf(" scaled %lld\n", w);*/
+               if (w < bucket->item_weights[i])
+                       return bucket->h.items[i];
+       }
+       
+       BUG_ON(1);
+       return 0;
+}
+
+
+/* tree */
+
+static int height(int n) {
+       int h = 0;
+       while ((n & 1) == 0) {
+               h++; 
+               n = n >> 1;
+       }
+       return h;
+}
+static int left(int x) {
+       int h = height(x);
+       return x - (1 << (h-1));
+}
+static int right(int x) {
+       int h = height(x);
+       return x + (1 << (h-1));
+}
+static int terminal(int x) {
+       return x & 1;
+}
+
+static int 
+crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r)
+{
+       int n, l;
+       __u32 w;
+       __u64 t;
+
+       /* start at root */
+       n = bucket->h.size >> 1;
+
+       while (!terminal(n)) {
+               /* pick point in [0, w) */
+               w = bucket->node_weights[n];
+               t = (__u64)crush_hash32_4(x, n, r, bucket->h.id) * (__u64)w;
+               t = t >> 32;
+               
+               /* left or right? */
+               l = left(n);
+               if (t < bucket->node_weights[l])
+                       n = l;
+               else
+                       n = right(n);
+       }
+
+       return bucket->h.items[n];
+}
+
+
+/* straw */
+
+static int 
+crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r)
+{
+       int i;
+       int high = 0;
+       __u64 high_draw = 0;
+       __u64 draw;
+       
+       for (i=0; i<bucket->h.size; i++) {
+               draw = crush_hash32_3(x, bucket->h.items[i], r);
+               draw &= 0xffff;
+               draw *= bucket->straws[i];
+               if (i == 0 || draw > high_draw) {
+                       high = i;
+                       high_draw = draw;
+               }
+       }
+       
+       return bucket->h.items[high];
+}
+
+
+
+
+/** crush proper **/
+
+
+/*
+ * choose numrep distinct items of given type
+ */
+static int crush_choose(struct crush_map *map,
+                       struct crush_bucket *bucket,
+                       int x, int numrep, int type,
+                       int *out, int firstn)
+{
+       int rep;
+       int ftotal, flocal;
+       int retry_descent, retry_bucket, skip_rep;
+       struct crush_bucket *in = bucket;
+       int r;
+       int i;
+       int item;
+       int itemtype;
+       int outpos;
+       int collide, bad;
+       
+       outpos = 0;
+
+       for (rep = 0; rep < numrep; rep++) {
+               /* keep trying until we get a non-out, non-colliding item */
+               ftotal = 0;
+               skip_rep = 0;
+               do {
+                       retry_descent = 0;
+                       in = bucket;               /* initial bucket */
+                       
+                       /* choose through intervening buckets */
+                       flocal = 0;
+                       do {
+                               retry_bucket = 0;
+                               r = rep;
+                               if (in->bucket_type == CRUSH_BUCKET_UNIFORM) {
+                                       /* be careful */
+                                       if (firstn || numrep >= in->size) 
+                                               r += ftotal;           /* r' = r + f_total */
+                                       else if (in->size % numrep == 0)
+                                               r += (numrep+1) * flocal; /* r'=r+(n+1)*f_local */
+                                       else
+                                               r += numrep * flocal; /* r' = r + n*f_local */                                          
+                               } else {
+                                       if (firstn) 
+                                               r += ftotal;           /* r' = r + f_total */
+                                       else 
+                                               r += numrep * flocal;  /* r' = r + n*f_local */
+                               }
+
+                               /* bucket choose */
+                               switch (in->bucket_type) {
+                               case CRUSH_BUCKET_UNIFORM:
+                                       item = crush_bucket_uniform_choose((struct crush_bucket_uniform*)in, x, r);
+                                       break;
+                               case CRUSH_BUCKET_LIST:
+                                       item = crush_bucket_list_choose((struct crush_bucket_list*)in, x, r);
+                                       break;
+                               case CRUSH_BUCKET_TREE:
+                                       item = crush_bucket_tree_choose((struct crush_bucket_tree*)in, x, r);
+                                       break;
+                               case CRUSH_BUCKET_STRAW:
+                                       item = crush_bucket_straw_choose((struct crush_bucket_straw*)in, x, r);
+                                       break;
+                               default:
+                                       BUG_ON(1);
+                               }
+                               
+                               /* desired type? */
+                               if (item < 0) 
+                                       itemtype = map->buckets[-1-item]->type;
+                               else 
+                                       itemtype = 0;
+                               
+                               /* keep going? */
+                               if (itemtype != type) {
+                                       BUG_ON(item >= 0 || (-1-item) >= map->max_buckets);
+                                       in = map->buckets[-1-item];
+                                       continue;
+                               }
+                               
+                               /* collision? */
+                               collide = 0;
+                               for (i=0; i<rep; i++) {
+                                       if (out[i] == item) {
+                                               collide = 1;
+                                               break;
+                                       }
+                               }
+                               
+                               /* bad (out)? */
+                               bad = 0;
+                               if (itemtype == 0 && map->device_offload[item]) {
+                                       if (map->device_offload[item] >= 0x10000) 
+                                               bad = 1;
+                                       else if ((crush_hash32_2(x, item) & 0xffff) < map->device_offload[item])
+                                               bad = 1;
+                               }
+                               
+                               if (bad || collide) {
+                                       ftotal++;
+                                       flocal++;
+                                       
+                                       if (collide && flocal < 3) 
+                                               retry_bucket = 1;  /* retry locally a few times */
+                                       else if (ftotal < 10)
+                                               retry_descent = 1; /* then retry descent */
+                                       else
+                                               skip_rep = 1;      /* else give up */
+                               }
+                       } while (retry_bucket);
+               } while (retry_descent);
+               
+               if (skip_rep) continue;
+
+               out[outpos] = item;
+               outpos++;
+       }
+       
+       return outpos;
+}
+
+
+int crush_do_rule(struct crush_map *map,
+                 int ruleno,
+                 int x, int *result, int result_max,
+                 int forcefeed)    /* -1 for none */
+{
+       int result_len;
+       int force_stack[CRUSH_MAX_DEPTH];
+       int force_pos = -1;
+       int a[CRUSH_MAX_SET];
+       int b[CRUSH_MAX_SET];
+       int *w;
+       int wsize = 0;
+       int *o;
+       int osize;
+       int *tmp;
+       struct crush_rule *rule;
+       int step;
+       int i;
+       int numrep;
+       
+       rule = map->rules[ruleno];
+       result_len = 0;
+       w = a;
+       o = b;
+       
+       /* determine hierarchical context of forcefeed, if any */
+       if (forcefeed >= 0) {
+               if (map->device_parents[forcefeed] == 0) {
+                       /*printf("CRUSH: forcefed device dne\n");*/
+                       return -1;  /* force fed device dne */
+               }
+               while (1) {
+                       force_stack[++force_pos] = forcefeed;
+                       /*printf("force_stack[%d] = %d\n", force_pos, forcefeed);*/
+                       if (forcefeed >= 0)
+                               forcefeed = map->device_parents[forcefeed];
+                       else
+                               forcefeed = map->bucket_parents[-1-forcefeed];
+                       if (forcefeed == 0) break;
+               }
+       }
+       
+       for (step = 0; step < rule->len; step++) {
+               switch (rule->steps[step].op) {
+               case CRUSH_RULE_TAKE:
+                       if (force_pos >= 0) {
+                               w[0] = force_stack[force_pos];
+                               force_pos--;
+                               BUG_ON(w[0] != rule->steps[step].arg1);
+                       } else {
+                               w[0] = rule->steps[step].arg1;
+                       }
+                       wsize = 1;
+                       break;
+                       
+               case CRUSH_RULE_CHOOSE_FIRSTN:
+               case CRUSH_RULE_CHOOSE_INDEP:
+                       BUG_ON(wsize == 0);
+                       
+                       /* reset output */
+                       osize = 0;
+                       
+                       for (i = 0; i < wsize; i++) {
+                               numrep = rule->steps[step].arg1;
+                               if (force_pos >= 0) {
+                                       o[osize++] = force_stack[force_pos];
+                                       force_pos--;
+                                       numrep--;
+                               }
+                               if (!numrep) continue;
+                               osize += crush_choose(map,
+                                                     map->buckets[-1-w[i]],
+                                                     x, numrep, rule->steps[step].arg2,
+                                                     o+osize, rule->steps[step].op == CRUSH_RULE_CHOOSE_FIRSTN);
+                       }
+                       
+                       /* swap t and w arrays */
+                       tmp = o;
+                       o = w;
+                       w = tmp;
+                       wsize = osize;
+                       break;      
+                       
+                       
+               case CRUSH_RULE_EMIT:
+                       for (i=0; i<wsize && result_max; i++) {
+                               result[result_len] = w[i];
+                               result_len++;
+                               result_max--;
+                       }
+                       wsize = 0;
+                       break;
+                       
+               default:
+                       BUG_ON(1);
+               }
+       }
+       
+       return result_len;
+}
+
+
diff --git a/trunk/ceph/crush/mapper.h b/trunk/ceph/crush/mapper.h
new file mode 100644 (file)
index 0000000..6c74539
--- /dev/null
@@ -0,0 +1,19 @@
+#ifndef _CRUSH_MAPPER_H
+#define _CRUSH_MAPPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "crush.h"
+
+extern int crush_do_rule(struct crush_map *map,
+                        int ruleno,
+                        int x, int *result, int result_max,
+                        int forcefeed); /* -1 for none */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/trunk/ceph/crush/test.c b/trunk/ceph/crush/test.c
new file mode 100644 (file)
index 0000000..041552b
--- /dev/null
@@ -0,0 +1,65 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "crush.h"
+#include "mapper.h"
+#include "builder.h"
+
+
+int main()
+{
+  int sub[10];
+  int subw[10];
+  int i, j;
+  int d;
+  int o[100];
+  int root;
+  int ruleno;
+  int r[10];
+  
+  int uw[10] = { 1000, 1000, 500, 1000, 2000, 1000, 1000, 3000, 1000, 500 };
+
+  struct crush_bucket *b;
+  struct crush_rule *rule;
+  
+  struct crush_map *map = crush_create();
+
+  d = 0;
+  for (i=0; i<10; i++) {
+    for (j=0; j<10; j++)
+      o[j] = d++;
+    b = (struct crush_bucket*)crush_make_uniform_bucket(1, 10, o, uw[i]);
+    sub[i] = crush_add_bucket(map, b);
+    subw[i] = b->weight;
+    printf("make bucket %d weight %d\n", sub[i], subw[i]);
+  }
+
+  root = crush_add_bucket(map, (struct crush_bucket*)crush_make_tree_bucket(2, 10, sub, subw));
+
+  rule = crush_make_rule();
+  crush_rule_add_step(rule, CRUSH_RULE_TAKE, root, 0);
+  crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 3, 1);
+  crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 1, 0);
+  crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+  ruleno = crush_add_rule(map, -1, rule);
+
+  crush_finalize(map);
+  printf("built\n");
+
+  /* test */
+  memset(o, 0, 100*sizeof(o[0]));
+  for (i=0; i<1000000; i++) {
+    crush_do_rule(map, ruleno, i, r, 3, -1);
+    /*printf("%d %d %d\n", r[0], r[1], r[2]);*/
+    for (j=0; j<3; j++)
+      o[r[j]]++;
+  }
+
+  for (i=0; i<100; i += 10)
+    printf("%2d : %d\n", i, o[i]); 
+
+  return 0;
+}
diff --git a/trunk/ceph/crush/test/bucket_movement.cc b/trunk/ceph/crush/test/bucket_movement.cc
deleted file mode 100644 (file)
index 6be1735..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       //if (bad)
-       // cout << "bad set " << x << ": " << v << endl;
-       
-       placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int n, float f, int buckettype)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-  int ndisks = 0;
-
-  // bucket
-  Bucket *b;
-  if (buckettype == 0)
-       b = new TreeBucket(1);
-  else if (buckettype == 1 || buckettype == 2)
-       b = new ListBucket(1);
-  else if (buckettype == 3)
-       b = new StrawBucket(1);
-  else if (buckettype == 4)
-       b = new UniformBucket(0,0);
-
-  for (int i=0; i<n; i++)
-       b->add_item(ndisks++,1);
-
-  c.add_bucket(b);
-  int root = b->get_id();
-  
-  //c.print(cout,root);
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 1000;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, vector<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  
-  // ORIGINAL
-  place(c, rule, numpg, numrep, placement1);
-  
-  int olddisks = ndisks;
-
-  // add item
-  if (buckettype == 2) {
-       // start over!
-       ndisks = 0;
-       b = new ListBucket(1);
-       for (int i=0; i<=n; i++)
-         b->add_item(ndisks++,1);
-       c.add_bucket(b);
-       root = b->get_id();
-
-       rule.steps.clear();
-       rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-       rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-       rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  }
-  else
-       b->add_item(ndisks++, 1);
-
-
-  // ADDED
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  int moved = 0;
-  for (int x=1; x<=numpg; x++) 
-       if (placement1[x] != placement2[x]) 
-         for (int j=0; j<numrep; j++)
-               if (placement1[x][j] != placement2[x][j]) 
-                 moved++;
-
-  int total = numpg*numrep;
-  float actual = (float)moved / (float)(total);
-  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
-  float fac = actual/ideal;
-  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
-  cout << "\t" << fac;
-  return fac;
-}
-
-
-int main() 
-{
-  //cout << "//  " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
-  cout << "n\ttree\tlhead\tltail\tstraw\tuniform" << endl;
-
-  //for (int s=2; s<=64; s+= (s<4?1:(s<16?2:4))) {
-  for (int s=2; s<=64; s+= (s<4?1:4)) {
-       float f = 1.0 / (float)s;
-       //cout << f << "\t" << s;
-       cout << s;
-       for (int buckettype=0; buckettype<5; buckettype++)
-         testmovement(s, f, buckettype);
-       cout << endl;
-  }
-}
-
diff --git a/trunk/ceph/crush/test/bucket_variance.cc b/trunk/ceph/crush/test/bucket_variance.cc
deleted file mode 100644 (file)
index d2f553f..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       //Bucket *b = new MixedBucket(h+1);
-       Bucket *b = new StrawBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-float go(int dep) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  if (0) {
-       for (int d=0; d<dep; d++)
-         wid.push_back(10);
-  }
-  if (1) {
-       if (dep == 0) 
-         wid.push_back(1000);
-       if (dep == 1) {
-         wid.push_back(1);
-         wid.push_back(1000);
-       }
-       if (dep == 2) {
-         wid.push_back(5);
-         wid.push_back(5);
-         wid.push_back(8);
-         wid.push_back(5);
-       }       
-  }
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  if (0) {
-       MixedBucket *b = new MixedBucket(1);
-       for (int i=0; i<10000; i++)
-         b->add_item(ndisks++, 10);
-       root = c.add_bucket(b);
-  }
-  if (0) {
-       vector<int> disks;
-       for (int i=0; i<10000; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
-       Hash h(123);
-       b->make_primes(h);
-       root = c.add_bucket(b);
-  }
-  
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 100000;
-  int times = place / numpg;
-  if (!times) times = 1;
-
-  cout << "#looping " << times << " times" << endl;
-  
-  float tvar = 0;
-  int tvarnum = 0;
-
-  int x = 0;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       for (int xx=1; xx<numpg; xx++) {
-         x++;
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         if (bad)
-               cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       
-       /*
-         for (int i=0; i<ocount.size(); i++) {
-         cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       */
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       
-       float avg = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         avg += ocount[i];
-       avg /= ocount.size();
-       float var = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         var += (ocount[i] - avg) * (ocount[i] - avg);
-       var /= ocount.size();
-       
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       //cout << avg << "\t";
-       
-       tvar += var;
-       tvarnum++;
-  }
-
-  tvar /= tvarnum;
-
-  //cout << "total variance " << tvar << endl;
-
-  return tvar;
-}
-
-
-int main() 
-{
-  for (int d=0; d<=2; d++) {
-       float var = go(d);
-       //cout << "## depth = " << d << endl;
-       cout << d << "\t" << var << "\t" << sqrt(var) << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/cluster_movement.cc b/trunk/ceph/crush/test/cluster_movement.cc
deleted file mode 100644 (file)
index aa1418a..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-int buckettype = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       //Bucket *b = new TreeBucket(h+1);
-       //Bucket *b = new ListBucket(h+1);
-       //Bucket *b = new StrawBucket(h+1);
-       Bucket *b;
-       if (buckettype == 0)
-         b = new TreeBucket(h+1);
-       else if (buckettype == 1 || buckettype == 2)
-         b = new ListBucket(h+1);
-       else if (buckettype == 3)
-         b = new StrawBucket(h+1);
-
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       
-       placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(udisks);
-  for (int d=1; d<depth; d++)
-       wid.push_back(branching);
-
-  map< int, list<Bucket*> > buckets;
-
-  root = make_hierarchy(c, wid, buckets, ndisks);
-  
-  //c.print(cout,root);
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, vector<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  
-  // ORIGINAL
-  place(c, rule, numpg, numrep, placement1);
-  
-  int olddisks = ndisks;
-
-  // add disks
-  //cout << " adding " << add << " disks" << endl;
-  vector<int> disks;
-  for (int i=0; i<add; i++)
-       disks.push_back(ndisks++);
-  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-  //b->make_primes(h);
-
-  //Bucket *o = buckets[2].back();
-  Bucket *o;
-  if (buckettype == 2)
-       o = buckets[modifydepth].front();
-  else
-       o = buckets[modifydepth].back();
-
-  c.add_bucket(b);
-  //cout << " adding under " << o->get_id() << endl;
-  c.add_item(o->get_id(), b->get_id(), b->get_weight());
-  //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
-  //newbucket = b;
-
-
-  // ADDED
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  int moved = 0;
-  for (int x=1; x<=numpg; x++) 
-       if (placement1[x] != placement2[x]) 
-         for (int j=0; j<numrep; j++)
-               if (placement1[x][j] != placement2[x][j]) 
-                 moved++;
-
-  int total = numpg*numrep;
-  float actual = (float)moved / (float)(total);
-  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
-  float fac = actual/ideal;
-  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
-  cout << "\t" << fac;
-  return fac;
-}
-
-
-int main() 
-{
-  
-  int udisks = 10;
-  int add = udisks;
-
-  //int depth = 3;
-  //int branching = 25;
-  int depth = 4;
-  int branching = 9;
-
-  int modifydepth = 1;
-  int bfac = (int)(sqrt((double)branching));
-  int n = (int)(udisks * pow((float)branching, (float)depth-1));
-
-  cout << "// depth " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
-  cout << "n\ttree\tlhead\tltail\tstraw" << endl;
-  for (int add = udisks; add <= n; add *= bfac) {
-       cout << add;
-       for (buckettype=0; buckettype<4; buckettype++)
-         testmovement(depth, branching, udisks, add, modifydepth);
-       cout << endl;
-  }
-}
-
diff --git a/trunk/ceph/crush/test/cluster_movement_remove.cc b/trunk/ceph/crush/test/cluster_movement_remove.cc
deleted file mode 100644 (file)
index 4a6560e..0000000
+++ /dev/null
@@ -1,229 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int buckettype = 2;  // 0 = mixed, 1 = linear, 2 = straw
-
-int big_one_skip = 255;
-int big_one_size;
-Bucket *big_one = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       
-       int s = wid[h];
-       if (big_one_skip > 0) 
-         big_one_skip--;         
-       if (!big_one_skip && !big_one)
-         s = big_one_size;
-
-
-       for (int i=0; i<s; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       if (!big_one_skip && !big_one) big_one = b;
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks " << disks.size()<< endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       Bucket *b;
-       if (buckettype == 0)
-         b = new TreeBucket(h+1);
-       else if (buckettype == 1)
-         b = new ListBucket(h+1);
-       else if (buckettype == 2)
-         b = new StrawBucket(h+1);
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       if (bad)
-         cout << "bad set " << x << ": " << v << endl;
-       
-       placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(udisks);
-  for (int d=1; d<depth; d++)
-       wid.push_back(branching + ((d==2)?1:0));
-
-  map< int, list<Bucket*> > buckets;
-
-  big_one_size = add;
-  big_one = 0;
-  
-  //cout << "making tree" << endl;
-  root = make_hierarchy(c, wid, buckets, ndisks);
-  
-  //c.print(cout, root);
-
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, vector<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  int olddisks = ndisks;
-
-
-  place(c, rule, numpg, numrep, placement1);
-  
-  if (1) {
-       // remove disks
-       assert(big_one);
-       c.adjust_item(big_one->get_id(), 0);
-  }
-
-  int newdisks = ndisks - add;
-
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  int moved = 0;
-  for (int x=1; x<=numpg; x++) 
-       if (placement1[x] != placement2[x]) 
-         for (int j=0; j<numrep; j++)
-               if (placement1[x][j] != placement2[x][j]) 
-                 moved++;
-
-  int total = numpg*numrep;
-  float actual = (float)moved / (float)(total);
-  //float ideal = (float)(newdisks-olddisks) / (float)(ndisks);
-  float ideal = (float)(olddisks-newdisks) / (float)(olddisks);
-  float fac = actual/ideal;
-  cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
-  return fac;
-}
-
-
-int main() 
-{
-  
-  int udisks = 10;
-  int ndisks = 10;
-  int depth = 4;
-  int branching = 9;
-  int add = udisks;
-
-  //cout << "\t" << n;
-  //  cout << endl;
-
-  buckettype = 2;  // 0 = tree, 1 = linear, 2 = straw
-
-  int n = udisks * pow((float)branching, (float)depth-1);
-  for (int add = udisks; add <= n; add *= 3) {
-       big_one_skip = 0;
-       big_one_skip = 9;
-       testmovement(depth, branching, udisks, add);
-  }
-  
-  /*
-  cout << "##" << endl;
-  for (map<int, map<float,float> >::iterator i = r.begin();
-          i != r.end();
-          i++) {
-       cout << i->first;
-       for (map<float,float>::iterator j = i->second.begin();
-                j != i->second.end();
-                j++)
-         cout << "\t" << j->first << "\t" << j->second;
-       cout << endl;
-  }
-  */
-}
-
diff --git a/trunk/ceph/crush/test/cluster_movement_rush.cc b/trunk/ceph/crush/test/cluster_movement_rush.cc
deleted file mode 100644 (file)
index 90cc197..0000000
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-int buckettype = 0;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       //Bucket *b = new TreeBucket(h+1);
-       //Bucket *b = new ListBucket(h+1);
-       //Bucket *b = new StrawBucket(h+1);
-       Bucket *b;
-       if (buckettype == 0)
-         b = new TreeBucket(h+1);
-       else if (buckettype == 1 || buckettype == 2)
-         b = new ListBucket(h+1);
-       else if (buckettype == 3)
-         b = new StrawBucket(h+1);
-
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       
-       placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks, int add, int modifydepth)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(udisks);
-  for (int d=1; d<depth; d++)
-       wid.push_back(branching);
-
-  map< int, list<Bucket*> > buckets;
-
-  root = make_hierarchy(c, wid, buckets, ndisks);
-  
-  //c.print(cout,root);
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, vector<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  
-  // ORIGINAL
-  place(c, rule, numpg, numrep, placement1);
-  
-  int olddisks = ndisks;
-
-  // add disks
-  //cout << " adding " << add << " disks" << endl;
-  vector<int> disks;
-  for (int i=0; i<add; i++)
-       disks.push_back(ndisks++);
-  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-  //b->make_primes(h);
-
-  //Bucket *o = buckets[2].back();
-  Bucket *o;
-  if (buckettype == 2)
-       o = buckets[modifydepth].front();
-  else
-       o = buckets[modifydepth].back();
-
-  c.add_bucket(b);
-  //cout << " adding under " << o->get_id() << endl;
-  c.add_item(o->get_id(), b->get_id(), b->get_weight(), buckettype == 2);
-  //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
-  //newbucket = b;
-
-
-  // ADDED
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  int moved = 0;
-  for (int x=1; x<=numpg; x++) 
-       if (placement1[x] != placement2[x]) 
-         for (int j=0; j<numrep; j++)
-               if (placement1[x][j] != placement2[x][j]) 
-                 moved++;
-
-  int total = numpg*numrep;
-  float actual = (float)moved / (float)(total);
-  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
-  float fac = actual/ideal;
-  //cout << add << "\t" << olddisks << "\t" << ndisks << "\t" << moved << "\t" << total << "\t" << actual << "\t" << ideal << "\t" << fac << endl;
-  cout << "\t" << fac;
-  return fac;
-}
-
-
-int main() 
-{
-  
-  int udisks = 10;
-  int add = udisks;
-
-  //int depth = 3;
-  //int branching = 25;
-  int depth = 2;
-  int branching = 9*9*9;
-
-  int modifydepth = 1;
-  int bfac = (int)(sqrt((double)branching));
-  bfac = 3;
-  int n = (int)(udisks * pow((float)branching, (float)depth-1));
-
-  cout << "// depth " << depth << ",  modifydepth " << modifydepth << ",  branching " << branching << ",  disks " << n << endl;
-  cout << "n\ttree\tlhead\tltail\tstraw" << endl;
-  for (int add = udisks; add <= n; add *= bfac) {
-       cout << add;
-       for (buckettype=0; buckettype<3; buckettype++)
-         testmovement(depth, branching, udisks, add, modifydepth);
-       cout << endl;
-  }
-}
-
diff --git a/trunk/ceph/crush/test/creeping_failure.cc b/trunk/ceph/crush/test/creeping_failure.cc
deleted file mode 100644 (file)
index ce27535..0000000
+++ /dev/null
@@ -1,276 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include "../../common/Clock.h"
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Clock g_clock;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       float w = 10;//((ndisks-1)/100+1)*10;
-       UniformBucket *b = new UniformBucket(1, 0, w, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b = new TreeBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-
-float go(int dep, int failpc) 
-{
-  Hash h(73232313);
-
-  //int overloadcutoff = (int)((float)10000.0 / (float)utilization);
-
-  //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  for (int d=0; d<dep; d++)
-       wid.push_back(10);
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-
-  //cout << ndisks << " disks" << endl;
-
-
-  int numf = ndisks * failpc / 100;
-
-
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-  int pg_per_base = 100;//20;
-  int pg_med = 10*pg_per_base;
-  int pg_per = pg_per_base*5.5;//100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 1000000;
-  int times = place / numpg;
-  if (!times) times = 1;
-  
-
-  //cout << "looping " << times << " times" << endl;
-  
-  float tavg[10];
-  float tvar[10];
-  for (int j=0;j<10;j++) {
-       tvar[j] = 0;
-       tavg[j] = 0;
-  }
-  int tvarnum = 0;
-  float trvar = 0.0;
-
-  float overloadsum = 0.0;
-  float adjustsum = 0.0;
-  float afteroverloadsum = 0.0;
-  float aslowdown = 0.0;
-  int chooses = 0;
-  int xs = 1;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       c.out.clear();
-
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-       
-       utime_t t1a = g_clock.now();
-       for (int x=xs; x<numpg+xs; x++) {
-         c.do_rule(rule, x, v);
-         //chooses += numrep;
-         for (int i=0; i<v.size(); i++) {
-               //if (v[i] >= ndisks) cout << "v[i] " << i << " is " << v[i] << "  .. x = " << x << endl;
-               //assert(v[i] < ndisks);
-               ocount[v[i]]++;
-         }
-       }
-       utime_t t1b = g_clock.now();
-
-       // add in numf failed disks
-       for (int f = 0; f < numf; f++) {
-         int d = rand() % ndisks;
-         while (c.out.count(d)) d = rand() % ndisks;
-         c.out.insert(d);
-       }
-
-       utime_t t3a = g_clock.now();
-       for (int x=xs; x<numpg+xs; x++) {
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         for (int i=0; i<v.size(); i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-         }
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       xs += numpg;
-
-       utime_t t3b = g_clock.now();
-
-       t1b -= t1a;
-       double t1 = (double)t1b;
-       t3b -= t3a;
-       double t3 = (double)t3b;
-       double slowdown = t3/t1;
-       //cout << "slowdown " << slowdown << endl;
-       aslowdown += slowdown;
-
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       // stair var calc
-       int n = ndisks/10;
-       float avg[10];
-       float var[10];
-       for (int i=0;i<10;i++) {
-         int s = n*i;
-         avg[i] = 0.0;
-         int nf = 0;
-         for (int j=0; j<n; j++) {
-               if (c.out.count(j+s)) { nf++; continue; }
-               avg[i] += ocount[j+s];
-         }
-         avg[i] /= (n-nf);//ocount.size();
-         var[i] = 0.0;
-         for (int j=0; j<n; j++) {
-               if (c.out.count(j+s)) continue;
-               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
-         }
-         var[i] /= (n-nf);//ocount.size();
-
-         tvar[i] += var[i];
-         tavg[i] += avg[i];
-       }
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       
-       tvarnum++;
-
-       // flat var calc
-       int na = ndisks - numf;  // num active
-       float ravg = 0.0;
-       for (int i=0;i<ndisks;i++) {
-         if (c.out.count(i)) continue;
-         ravg += ocount[i];
-       }
-       ravg /= (float)na;
-       float rvar = 0.0;
-       for (int i=0; i<ndisks; i++) {
-         if (c.out.count(i)) continue;
-         rvar += (ravg-(float)ocount[i])*(ravg-(float)ocount[i]);
-       }
-       rvar /= (float)na;
-
-       trvar += rvar;
-  }
-
-
-  trvar /= (float)tvarnum;
-
-  //overloadsum /= tvarnum;
-  //adjustsum /= tvarnum;
-  float avar = 0.0;
-  for (int j=0;j<10;j++) {
-       tvar[j] /= tvarnum;
-       tavg[j] /= tvarnum;
-       avar += tvar[j];
-  }
-  avar /= 10;
-  avar = sqrt(avar);
-  avar /= /*5.5 **/ (float)pg_per_base;
-  //afteroverloadsum /= tvarnum;
-  aslowdown /= tvarnum;
-
-  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
-  //float crate = (float) collisions / (float)chooses;
-  //cout << "collisions: " << c.collisions << endl;
-
-
-  //cout << "total variance " << tvar << endl;
-  //cout << " overlaod " << overloadsum << endl;
-  
-  cout << failpc 
-          << "\t" << numf 
-       //<< "\t" << adjustsum 
-       //<< "\t" << afteroverloadsum 
-          << "\t" << aslowdown 
-          << "\t" << trvar
-          << "\t" << sqrt(trvar) / (float)pg_per_base
-          << "\t..\t" << avar 
-          << "\t-"; 
-
-  for (int i=0;i<10;i++)
-       cout << "\t" << tavg[i] << "\t" << sqrt(tvar[i]);// << "\t" << tvar[i]/tavg[i];
-
-  cout << endl;
-  return tvar[0];
-}
-
-
-int main() 
-{
-  for (int pc = 0; pc < 90; pc += 5) {
-       float var = go(3, pc);
-  }
-  
-
-}
diff --git a/trunk/ceph/crush/test/creeping_failure_variance.cc b/trunk/ceph/crush/test/creeping_failure_variance.cc
deleted file mode 100644 (file)
index c7a65a0..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       MixedBucket *b = new MixedBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
-{
-  int w = rand() % (wid-1) + 2;
-
-  if (height == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<w; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       int h = rand() % height + 1;
-       MixedBucket *b = new MixedBucket(h+1);
-       for (int i=0; i<w; i++) {
-         Bucket *n = make_random(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-
-}
-
-
-float go(int dep, int overloadcutoff) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  for (int d=0; d<dep; d++)
-       wid.push_back(10);
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  if (0) {
-       Bucket *r = make_random(c, 20,  4, ndisks);
-       root = r->get_id();
-       //c.print(cout, root);
-  }
-  if (0) {
-       MixedBucket *b = new MixedBucket(1);
-       for (int i=0; i<10000; i++)
-         b->add_item(ndisks++, 10);
-       root = c.add_bucket(b);
-  }
-  if (0) {
-       vector<int> disks;
-       for (int i=0; i<10000; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
-       Hash h(123);
-       b->make_primes(h);
-       root = c.add_bucket(b);
-  }
-  //cout << ndisks << " disks" << endl;
-  
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 1000000;
-  int times = place / numpg;
-  if (!times) times = 1;
-  
-
-  //cout << "looping " << times << " times" << endl;
-  
-  float tvar = 0;
-  int tvarnum = 0;
-
-  float overloadsum = 0.0;
-  float adjustsum = 0.0;
-  float afteroverloadsum = 0.0;
-  int chooses = 0;
-  int xs = 1;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       c.overload.clear();
-
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         chooses += numrep;
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         if (bad)
-               cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-
-       // overloaded?
-       int overloaded = 0;
-       int adjusted = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         if (ocount[i] > overloadcutoff) 
-               overloaded++;
-
-         if (ocount[i] > 100+(overloadcutoff-100)/2) {
-               adjusted++;
-               c.overload[i] = 100.0 / (float)ocount[i];
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-         ocount[i] = 0;
-       }
-       //cout << overloaded << " overloaded" << endl;
-       overloadsum += (float)overloaded / (float)ndisks;
-       adjustsum += (float)adjusted / (float)ndisks;
-
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         if (bad)
-               cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       xs += numpg;
-
-       int still = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         if (ocount[i] > overloadcutoff) {
-               still++;
-               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       }
-       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
-       afteroverloadsum += (float)still / (float)ndisks;
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       float avg = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         avg += ocount[i];
-       avg /= ocount.size();
-       float var = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         var += (ocount[i] - avg) * (ocount[i] - avg);
-       var /= ocount.size();
-       
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       
-       tvar += var;
-       tvarnum++;
-  }
-
-  overloadsum /= tvarnum;
-  adjustsum /= tvarnum;
-  tvar /= tvarnum;
-  afteroverloadsum /= tvarnum;
-
-  int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
-  float crate = (float) collisions / (float)chooses;
-  //cout << "collisions: " << c.collisions << endl;
-
-
-  //cout << "total variance " << tvar << endl;
-  //cout << " overlaod " << overloadsum << endl;
-
-  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
-  return tvar;
-}
-
-
-int main() 
-{
-  for (int d=140; d>100; d -= 5) {
-       float var = go(3,d);
-       //cout << "## depth = " << d << endl;
-       //cout << d << "\t" << var << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/depth_variance.cc b/trunk/ceph/crush/test/depth_variance.cc
deleted file mode 100644 (file)
index 7d60eba..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b = new TreeBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-float go(int dep) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  if (1) {
-       for (int d=0; d<dep; d++)
-         wid.push_back(10);
-  }
-  if (0) {
-       if (dep == 0) 
-         wid.push_back(1000);
-       if (dep == 1) {
-         wid.push_back(1);
-         wid.push_back(1000);
-       }
-       if (dep == 2) {
-         wid.push_back(5);
-         wid.push_back(5);
-         wid.push_back(8);
-         wid.push_back(5);
-       }       
-  }
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 100000;
-  int times = place / numpg;
-  if (!times) times = 1;
-
-  cout << "#looping " << times << " times" << endl;
-  
-  float tvar = 0;
-  int tvarnum = 0;
-  float tavg = 0;
-
-  int x = 0;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       for (int xx=1; xx<numpg; xx++) {
-         x++;
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       
-       /*
-         for (int i=0; i<ocount.size(); i++) {
-         cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       */
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       
-       float avg = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         avg += ocount[i];
-       avg /= ocount.size();
-       float var = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         var += (ocount[i] - avg) * (ocount[i] - avg);
-       var /= ocount.size();
-       
-       if (times < 10) 
-         cout << "avg " << avg << "   evar " << sqrt(avg) << "   sd " << sqrt(var) << endl;
-       //cout << avg << "\t";
-       
-       tvar += var;
-       tavg += avg;
-       tvarnum++;
-  }
-
-  tavg /= tvarnum;
-  tvar /= tvarnum;
-
-  cout << "total variance " << sqrt(tvar) << "   expected " << sqrt(tavg) << endl;
-
-  return tvar;
-}
-
-
-int main() 
-{
-  for (int d=2; d<=5; d++) {
-       float var = go(d);
-       //cout << "## depth = " << d << endl;
-       //cout << d << "\t" << var << "\t" << sqrt(var) << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/mixed.cc b/trunk/ceph/crush/test/mixed.cc
deleted file mode 100644 (file)
index 5666f7b..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       float w = ((ndisks-1)/100+1)*10;
-       UniformBucket *b = new UniformBucket(1, 0, w, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b = new TreeBucket(h+1);
-       //Bucket *b = new StrawBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-
-float go(int dep, int overloadcutoff) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  for (int d=0; d<dep; d++)
-       wid.push_back(10);
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per_base = 10;
-  int pg_per = pg_per_base*5.5;//100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 100000;
-  int times = place / numpg;
-  if (!times) times = 1;
-  
-
-  //cout << "looping " << times << " times" << endl;
-  
-  float tavg[10];
-  float tvar[10];
-  for (int j=0;j<10;j++) {
-       tvar[j] = 0;
-       tavg[j] = 0;
-  }
-  int tvarnum = 0;
-
-  float overloadsum = 0.0;
-  float adjustsum = 0.0;
-  float afteroverloadsum = 0.0;
-  int chooses = 0;
-  int xs = 1;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       c.overload.clear();
-
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         chooses += numrep;
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         //if (bad)
-         //cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-
-       // overloaded?
-       int overloaded = 0;
-       int adjusted = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         int target = (i/100+1)*10;
-         int cutoff = target * overloadcutoff / 100;
-         int adjoff = target + (cutoff - target)*3/4;
-         if (ocount[i] > cutoff) 
-               overloaded++;
-
-         if (ocount[i] > adjoff) {
-               adjusted++;
-               c.overload[i] = (float)target / (float)ocount[i];
-               //cout << "setting overload " << i << " to " << c.overload[i] << endl;
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-         ocount[i] = 0;
-       }
-       //cout << overloaded << " overloaded" << endl;
-       overloadsum += (float)overloaded / (float)ndisks;
-       adjustsum += (float)adjusted / (float)ndisks;
-
-
-
-       if (1) {
-         // second pass
-         for (int x=xs; x<numpg+xs; x++) {
-               
-               //cout << H(x) << "\t" << h(x) << endl;
-               c.do_rule(rule, x, v);
-               //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-               
-               bool bad = false;
-               for (int i=0; i<numrep; i++) {
-                 //int d = b.choose_r(x, i, h);
-                 //v[i] = d;
-                 ocount[v[i]]++;
-                 for (int j=i+1; j<numrep; j++) {
-                       if (v[i] == v[j]) 
-                         bad = true;
-                 }
-               }
-               
-               //cout << v << "\t" << ocount << endl;
-         }
-
-         for (int i=0; i<ocount.size(); i++) {
-               int target = (i/100+1)*10;
-               int cutoff = target * overloadcutoff / 100;
-               int adjoff = cutoff;//target + (cutoff - target)*3/4;
-
-               if (ocount[i] >= adjoff) {
-                 adjusted++;
-                 if (c.overload.count(i) == 0) {
-                       c.overload[i] = 1.0;
-                       adjusted++;
-                 }
-                 //else cout << "(re)adjusting " << i << endl;
-                 c.overload[i] *= (float)target / (float)ocount[i];
-                 //cout << "setting overload " << i << " to " << c.overload[i] << endl;
-                 //cout << "disk " << i << " has " << ocount[i] << endl;
-               }
-               ocount[i] = 0;
-         }
-       }
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         //cout << v << "\t" << ocount << endl;
-       }
-       xs += numpg;
-
-       int still = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         int target = (i/100+1)*10;
-         int cutoff = target * overloadcutoff / 100;
-         int adjoff = target + (cutoff - target)/3;
-
-         if (ocount[i] > cutoff) {
-               still++;
-               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
-               if (c.overload.count(i)) cout << "[adjusted] ";
-               cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       }
-       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
-       afteroverloadsum += (float)still / (float)ndisks;
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       int n = ndisks/10;
-       float avg[10];
-       float var[10];
-       for (int i=0;i<10;i++) {
-         int s = n*i;
-         avg[i] = 0.0;
-         for (int j=0; j<n; j++)
-               avg[i] += ocount[j+s];
-         avg[i] /= n;//ocount.size();
-         var[i] = 0.0;
-         for (int j=0; j<n; j++)
-               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
-         var[i] /= n;//ocount.size();
-
-         tvar[i] += var[i];
-         tavg[i] += avg[i];
-       }
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       
-       tvarnum++;
-  }
-
-  overloadsum /= tvarnum;
-  adjustsum /= tvarnum;
-  for (int j=0;j<10;j++) {
-       tvar[j] /= tvarnum;
-       tavg[j] /= tvarnum;
-  }
-  afteroverloadsum /= tvarnum;
-
-  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
-  //float crate = (float) collisions / (float)chooses;
-  //cout << "collisions: " << c.collisions << endl;
-
-
-  //cout << "total variance " << tvar << endl;
-  //cout << " overlaod " << overloadsum << endl;
-  
-  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum;
-  for (int i=0;i<10;i++)
-       cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
-  cout << endl;
-  return tvar[0];
-}
-
-
-int main() 
-{
-  float var = go(3,200);
-  for (int d=140; d>100; d -= 5) {
-       float var = go(3,d);
-       //cout << "## depth = " << d << endl;
-       //cout << d << "\t" << var << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/movement.cc b/trunk/ceph/crush/test/movement.cc
deleted file mode 100644 (file)
index 2621f09..0000000
+++ /dev/null
@@ -1,223 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       MixedBucket *b = new MixedBucket(h+1);
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, vector<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       if (bad)
-         cout << "bad set " << x << ": " << v << endl;
-       
-       placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(udisks);
-  for (int d=1; d<depth; d++)
-       wid.push_back(branching);
-
-  map< int, list<Bucket*> > buckets;
-
-  if (1) {
-       root = make_hierarchy(c, wid, buckets, ndisks);
-  }
-  if (0) {
-       MixedBucket *b = new MixedBucket(1);
-       for (int i=0; i<10000; i++)
-         b->add_item(ndisks++, 10);
-       root = c.add_bucket(b);
-  }
-  if (0) {
-       vector<int> disks;
-       for (int i=0; i<10000; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       Hash h(123);
-       b->make_primes(h);
-       root = c.add_bucket(b);
-  }
-  
-
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, vector<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  place(c, rule, numpg, numrep, placement1);
-  
-  if (1) {
-       // failed
-
-       //for (int i=500; i<1000; i++)
-       //c.failed.insert(i);
-       c.failed.insert(0);
-  }
-
-  int olddisks = ndisks;
-
-  if (1) {
-       int n = udisks;
-       //cout << " adding " << n << " disks" << endl;
-       vector<int> disks;
-       for (int i=0; i<n; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       Hash h(123);
-       b->make_primes(h);
-       Bucket *o = buckets[1].back();
-       c.add_bucket(b);
-       //cout << " adding under " << o->get_id() << endl;
-       c.add_item(o->get_id(), b->get_id(), b->get_weight());
-       //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
-  }
-
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  int moved = 0;
-  for (int x=1; x<=numpg; x++) {
-       if (placement1[x] != placement2[x]) {
-         for (int j=0; j<numrep; j++)
-               if (placement1[x][j] != placement2[x][j]) 
-                 moved++;
-         
-       }
-  }
-
-  float f = (float)moved / (float)(numpg*numrep);
-  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
-  float fac = f/ideal;
-  //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac <<  endl;
-  return fac;
-}
-
-
-int main() 
-{
-  
-  int udisks = 10;
-  int ndisks = 10;
-  for (int depth = 2; depth <= 4; depth++) {
-       vector<float> v;
-       cout << depth;
-       for (int branching = 3; branching < 16; branching += 1) {
-         float fac = testmovement(depth, branching, udisks);
-         v.push_back(fac);
-       int n = udisks * pow((float)branching, (float)depth-1);
-       cout << "\t" << n;
-         cout << "\t" << fac;
-       }
-       //for (int i=0; i<v.size(); i++)
-       //cout << "\t" << v[i];
-       cout << endl;
-
-  }
-
-}
-
diff --git a/trunk/ceph/crush/test/movement_failed.cc b/trunk/ceph/crush/test/movement_failed.cc
deleted file mode 100644 (file)
index 98c34d9..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       MixedBucket *b = new MixedBucket(h+1);
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, map<int, set<int> >& placement)
-{
-  vector<int> v(numrep);
-  map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-         placement[v[i]].insert(x);
-       }
-       if (bad)
-         cout << "bad set " << x << ": " << v << endl;
-       
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-  if (0) 
-       for (map<int,int>::iterator it = ocount.begin();
-                it != ocount.end();
-                it++) 
-         cout << it->first << "\t" << it->second << endl;
-
-}
-
-
-float testmovement(int depth, int branching, int udisks)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(udisks);
-  for (int d=1; d<depth; d++)
-       wid.push_back(branching);
-
-  map< int, list<Bucket*> > buckets;
-
-  if (1) {
-       root = make_hierarchy(c, wid, buckets, ndisks);
-  }
-  if (0) {
-       MixedBucket *b = new MixedBucket(1);
-       for (int i=0; i<10000; i++)
-         b->add_item(ndisks++, 10);
-       root = c.add_bucket(b);
-  }
-  if (0) {
-       vector<int> disks;
-       for (int i=0; i<10000; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       Hash h(123);
-       b->make_primes(h);
-       root = c.add_bucket(b);
-  }
-  
-
-
-  // rule
-  int numrep = 2;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  /*
-  cout << ndisks << " disks, " << endl;
-  cout << pg_per << " pgs per disk" << endl;
-    cout << numpg << " logical pgs" << endl;
-  cout << "numrep is " << numrep << endl;
-  */
-  map<int, set<int> > placement1, placement2;
-
-  //c.print(cout, root);
-
-  place(c, rule, numpg, numrep, placement1);
-
-  float over = .5;
-  
-  if (1) {
-       // failed
-
-       //for (int i=500; i<1000; i++)
-       //c.failed.insert(i);
-       //c.failed.insert(0);
-       c.overload[0] = over;
-  }
-
-  int olddisks = ndisks;
-
-
-
-  if (0) {
-       int n = udisks;
-       //cout << " adding " << n << " disks" << endl;
-       vector<int> disks;
-       for (int i=0; i<n; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       Hash h(123);
-       b->make_primes(h);
-       Bucket *o = buckets[1].back();
-       c.add_bucket(b);
-       //cout << " adding under " << o->get_id() << endl;
-       c.add_item(o->get_id(), b->get_id(), b->get_weight());
-       //((MixedBucket*)o)->add_item(b->get_id(), b->get_weight());
-  }
-
-  //c.print(cout, root);
-  place(c, rule, numpg, numrep, placement2);
-
-  vector<int> moved(ndisks);
-
-  //int moved = 0;
-  for (int d=0; d<ndisks; d++) {
-       for (set<int>::iterator it = placement1[d].begin();
-                it != placement1[d].end();
-                it++) {
-         placement2[d].erase(*it);
-       }
-  }
-
-  float avg = 0;
-  for (int d=0; d<ndisks; d++) {
-       moved[d] = placement2[d].size();
-       avg += moved[d];
-  }
-  avg /= (float)ndisks;
-  float var = 0;
-  for (int d=0; d<ndisks; d++) {
-       var += (moved[d]-avg)*(moved[d]-avg);
-  }
-  var /= (float)ndisks;
-
-  float expected = over * 100.0 / (float)(ndisks-1);
-
-  cout << ndisks << "\t" << expected << "\t" << avg << "\t" << var << endl;
-  /*
-  float f = (float)moved / (float)(numpg*numrep);
-  float ideal = (float)(ndisks-olddisks) / (float)(ndisks);
-  float fac = f/ideal;
-  //cout << moved << " moved or " << f << ", ideal " << ideal << ", factor of " << fac <<  endl;
-  return fac;
-  */
-}
-
-
-int main() 
-{
-  
-  int udisks = 10;
-  int ndisks = 10;
-  for (int depth = 2; depth <= 4; depth++) {
-       vector<float> v;
-       cout << depth;
-       for (int branching = 3; branching < 16; branching += 1) {
-         float fac = testmovement(depth, branching, udisks);
-         v.push_back(fac);
-         int n = udisks * pow((float)branching, (float)depth-1);
-         //cout << "\t" << n;
-         //cout << "\t" << fac;
-       }
-       //for (int i=0; i<v.size(); i++)
-       //cout << "\t" << v[i];
-       //cout << endl;
-
-  }
-
-}
-
diff --git a/trunk/ceph/crush/test/overload.cc b/trunk/ceph/crush/test/overload.cc
deleted file mode 100644 (file)
index 32c6672..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include "../../common/Clock.h"
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Clock g_clock;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       float w = ((ndisks-1)/100+1)*10;
-       UniformBucket *b = new UniformBucket(1, 0, w, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks weight " << w << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b = new TreeBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-
-float go(int dep, int utilization ) 
-{
-  Hash h(73232313);
-
-  int overloadcutoff = (int)((float)10000.0 / (float)utilization);
-
-  //cout << "util " << utilization << " cutoff " << overloadcutoff << endl;
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  for (int d=0; d<dep; d++)
-       wid.push_back(10);
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-
-  //cout << ndisks << " disks" << endl;
-  
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-  int pg_per_base = 20;
-  int pg_med = 10*pg_per_base;
-  int pg_per = pg_per_base*5.5;//100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 100000;
-  int times = place / numpg;
-  if (!times) times = 1;
-  
-
-  //cout << "looping " << times << " times" << endl;
-  
-  float tavg[10];
-  float tvar[10];
-  for (int j=0;j<10;j++) {
-       tvar[j] = 0;
-       tavg[j] = 0;
-  }
-  int tvarnum = 0;
-
-  float overloadsum = 0.0;
-  float adjustsum = 0.0;
-  float afteroverloadsum = 0.0;
-  float aslowdown = 0.0;
-  int chooses = 0;
-  int xs = 1;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       c.overload.clear();
-
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       
-       utime_t t1a = g_clock.now();
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         chooses += numrep;
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-         }
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-
-       utime_t t1b = g_clock.now();
-
-       // overloaded?
-       int overloaded = 0;
-       int adjusted = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         int target = (i/100+1)*pg_per_base;
-         int cutoff = target * overloadcutoff / 100;
-         int adjoff = target + (cutoff - target)*3/4;
-         if (ocount[i] > cutoff) 
-               overloaded++;
-
-         if (ocount[i] > adjoff) {
-               adjusted++;
-               c.overload[i] = (float)target / (float)ocount[i];
-               //cout << "setting overload " << i << " to " << c.overload[i] << endl;
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-         ocount[i] = 0;
-       }
-       //cout << overloaded << " overloaded" << endl;
-       overloadsum += (float)overloaded / (float)ndisks;
-       adjustsum += (float)adjusted / (float)ndisks;
-
-
-
-       // keep adjusting!
-       for (int bla=0; bla<5; bla++) {
-         utime_t t2a = g_clock.now();
-
-         // second pass
-         for (int x=xs; x<numpg+xs; x++) {
-               
-               //cout << H(x) << "\t" << h(x) << endl;
-               c.do_rule(rule, x, v);
-               //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-               
-               for (int i=0; i<numrep; i++) {
-                 //int d = b.choose_r(x, i, h);
-                 //v[i] = d;
-                 ocount[v[i]]++;
-               }
-               
-               //cout << v << "\t" << ocount << endl;
-         }
-
-         utime_t t2b = g_clock.now();
-
-         int numover = 0;
-         for (int i=0; i<ocount.size(); i++) {
-               int target = (i/100+1)*pg_per_base;
-               int cutoff = target * overloadcutoff / 100;
-               int adjoff = cutoff;//target + (cutoff - target)*3/4;
-
-               if (ocount[i] >= adjoff) {
-                 numover++;
-                 if (c.overload.count(i) == 0) {
-                       c.overload[i] = 1.0;
-                       adjusted++;
-                 }
-                 //else cout << "(re)adjusting " << i << endl;
-                 c.overload[i] *= (float)target / (float)ocount[i];
-                 //cout << "setting overload " << i << " to " << c.overload[i] << endl;
-                 //cout << "disk " << i << " has " << ocount[i] << endl;
-               }
-               ocount[i] = 0;
-         }
-         if (!numover) break;
-         cout << "readjusting" << endl;
-       }
-
-       utime_t t3a = g_clock.now();
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-         }
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       xs += numpg;
-
-       utime_t t3b = g_clock.now();
-
-       t1b -= t1a;
-       double t1 = (double)t1b;
-       t3b -= t3a;
-       double t3 = (double)t3b;
-       double slowdown = t3/t1;
-       //cout << "slowdown " << slowdown << endl;
-       aslowdown += slowdown;
-
-       int still = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         int target = (i/100+1)*pg_per_base;
-         int cutoff = target * overloadcutoff / 100;
-         //int adjoff = target + (cutoff - target)/3;
-
-         if (ocount[i] > cutoff) {
-               still++;
-               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
-               if (c.overload.count(i)) cout << "[adjusted] ";
-               cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       }
-       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
-       afteroverloadsum += (float)still / (float)ndisks;
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       int n = ndisks/10;
-       float avg[10];
-       float var[10];
-       for (int i=0;i<10;i++) {
-         int s = n*i;
-         avg[i] = 0.0;
-         for (int j=0; j<n; j++)
-               avg[i] += ocount[j+s];
-         avg[i] /= n;//ocount.size();
-         var[i] = 0.0;
-         for (int j=0; j<n; j++)
-               var[i] += (ocount[j+s] - avg[i]) * (ocount[j+s] - avg[i]);
-         var[i] /= n;//ocount.size();
-
-         tvar[i] += var[i];
-         tavg[i] += avg[i];
-       }
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       
-       tvarnum++;
-  }
-
-  overloadsum /= tvarnum;
-  adjustsum /= tvarnum;
-  float avar = 0.0;
-  for (int j=0;j<10;j++) {
-       tvar[j] /= tvarnum;
-       tavg[j] /= tvarnum;
-       avar += tvar[j];
-  }
-  avar /= 10;
-  avar = sqrt(avar);
-  avar /= 5.5 * (float)pg_per_base;
-  afteroverloadsum /= tvarnum;
-  aslowdown /= tvarnum;
-
-  //int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
-  //float crate = (float) collisions / (float)chooses;
-  //cout << "collisions: " << c.collisions << endl;
-
-
-  //cout << "total variance " << tvar << endl;
-  //cout << " overlaod " << overloadsum << endl;
-  
-  cout << overloadcutoff << "\t" << utilization 
-          << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum 
-          << "\t" << aslowdown << "\t" << avar << "\t-"; 
-
-  for (int i=0;i<10;i++)
-       cout << "\t" << tavg[i] << "\t" << tvar[i];// << "\t" << tvar[i]/tavg[i];
-  cout << endl;
-  return tvar[0];
-}
-
-
-int main() 
-{
-  float var = go(3,50);
-  /*  for (int d=70; d<100; d += 5) {
-       float var = go(3,d);
-       //cout << "## depth = " << d << endl;
-       //cout << d << "\t" << var << endl;
-       }*/
-  go(3,96);
-  go(3,97);
-  go(3,98);
-  go(3,99);
-  
-
-}
diff --git a/trunk/ceph/crush/test/overload_variance.cc b/trunk/ceph/crush/test/overload_variance.cc
deleted file mode 100644 (file)
index b04cae0..0000000
+++ /dev/null
@@ -1,281 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       MixedBucket *b = new MixedBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-Bucket *make_random(Crush& c, int wid, int height, int& ndisks)
-{
-  int w = rand() % (wid-1) + 2;
-
-  if (height == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<w; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       int h = rand() % height + 1;
-       MixedBucket *b = new MixedBucket(h+1);
-       for (int i=0; i<w; i++) {
-         Bucket *n = make_random(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-
-}
-
-
-float go(int dep, int overloadcutoff) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  for (int d=0; d<dep; d++)
-       wid.push_back(10);
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  if (0) {
-       Bucket *r = make_random(c, 20,  4, ndisks);
-       root = r->get_id();
-       //c.print(cout, root);
-  }
-  if (0) {
-       MixedBucket *b = new MixedBucket(1);
-       for (int i=0; i<10000; i++)
-         b->add_item(ndisks++, 10);
-       root = c.add_bucket(b);
-  }
-  if (0) {
-       vector<int> disks;
-       for (int i=0; i<10000; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10000, disks);
-       Hash h(123);
-       b->make_primes(h);
-       root = c.add_bucket(b);
-  }
-  //cout << ndisks << " disks" << endl;
-  
-
-
-  // rule
-  int numrep = 1;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-
-  int pg_per = 100;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-  //cout << ndisks << " disks, " << endl;
-  //cout << pg_per << " pgs per disk" << endl;
-  //  cout << numpg << " logical pgs" << endl;
-  //cout << "numrep is " << numrep << endl;
-
-
-  int place = 1000000;
-  int times = place / numpg;
-  if (!times) times = 1;
-  
-
-  //cout << "looping " << times << " times" << endl;
-  
-  float tvar = 0;
-  int tvarnum = 0;
-
-  float overloadsum = 0.0;
-  float adjustsum = 0.0;
-  float afteroverloadsum = 0.0;
-  int chooses = 0;
-  int xs = 1;
-  for (int t=0; t<times; t++) {
-       vector<int> v(numrep);
-       
-       c.overload.clear();
-
-       for (int z=0; z<ndisks; z++) ocount[z] = 0;
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         chooses += numrep;
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         if (bad)
-               cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-
-       // overloaded?
-       int overloaded = 0;
-       int adjusted = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         if (ocount[i] > overloadcutoff) 
-               overloaded++;
-
-         if (ocount[i] > 100+(overloadcutoff-100)/2) {
-               adjusted++;
-               c.overload[i] = 100.0 / (float)ocount[i];
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-         ocount[i] = 0;
-       }
-       //cout << overloaded << " overloaded" << endl;
-       overloadsum += (float)overloaded / (float)ndisks;
-       adjustsum += (float)adjusted / (float)ndisks;
-
-
-       for (int x=xs; x<numpg+xs; x++) {
-
-         //cout << H(x) << "\t" << h(x) << endl;
-         c.do_rule(rule, x, v);
-         //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-         
-         bool bad = false;
-         for (int i=0; i<numrep; i++) {
-               //int d = b.choose_r(x, i, h);
-               //v[i] = d;
-               ocount[v[i]]++;
-               for (int j=i+1; j<numrep; j++) {
-                 if (v[i] == v[j]) 
-                       bad = true;
-               }
-         }
-         if (bad)
-               cout << "bad set " << x << ": " << v << endl;
-         
-         //cout << v << "\t" << ocount << endl;
-       }
-       xs += numpg;
-
-       int still = 0;
-       for (int i=0; i<ocount.size(); i++) {
-         if (ocount[i] > overloadcutoff) {
-               still++;
-               //c.overload[ocount[i]] = 100.0 / (float)ocount[i];
-               //cout << "disk " << i << " has " << ocount[i] << endl;
-         }
-       }
-       //if (still) cout << "overload was " << overloaded << " now " << still << endl;
-       afteroverloadsum += (float)still / (float)ndisks;
-       
-       //cout << "collisions: " << c.collisions << endl;
-       //cout << "r bumps: " << c.bumps << endl;
-       
-       float avg = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         avg += ocount[i];
-       avg /= ocount.size();
-       float var = 0.0;
-       for (int i=0; i<ocount.size(); i++)
-         var += (ocount[i] - avg) * (ocount[i] - avg);
-       var /= ocount.size();
-       
-       //cout << "avg " << avg << "  var " << var << "   sd " << sqrt(var) << endl;
-       
-       tvar += var;
-       tvarnum++;
-  }
-
-  overloadsum /= tvarnum;
-  adjustsum /= tvarnum;
-  tvar /= tvarnum;
-  afteroverloadsum /= tvarnum;
-
-  int collisions = c.collisions[0] + c.collisions[1] + c.collisions[2] + c.collisions[3];
-  float crate = (float) collisions / (float)chooses;
-  //cout << "collisions: " << c.collisions << endl;
-
-
-  //cout << "total variance " << tvar << endl;
-  //cout << " overlaod " << overloadsum << endl;
-
-  cout << overloadcutoff << "\t" << (10000.0 / (float)overloadcutoff) << "\t" << tvar << "\t" << overloadsum << "\t" << adjustsum << "\t" << afteroverloadsum << "\t" << crate << endl;
-  return tvar;
-}
-
-
-int main() 
-{
-  for (int d=140; d>100; d -= 5) {
-       float var = go(3,d);
-       //cout << "## depth = " << d << endl;
-       //cout << d << "\t" << var << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/sizes.cc b/trunk/ceph/crush/test/sizes.cc
deleted file mode 100644 (file)
index cc57802..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-
-#include "include/types.h"
-#include "include/Distribution.h"
-#include "osd/OSDMap.h"
-
-
-Distribution file_size_distn; //kb
-
-
-list<int> object_queue;
-int max_object_size = 1024*1024*100;  //kb
-
-off_t no;
-
-int get_object()  //kb
-{
-  if (object_queue.empty()) {
-       int max = file_size_distn.sample();
-       no++;
-       int filesize = max/2 + (rand() % 100) * max/200 + 1;
-       //cout << "file " << filesize << endl;
-       while (filesize > max_object_size) {
-         object_queue.push_back(max_object_size);
-         filesize -= max_object_size;
-       }
-       object_queue.push_back(filesize);
-  }
-  int s = object_queue.front();
-  object_queue.pop_front();
-  //cout << "object " << s << endl;
-  return s;
-}
-
-void getdist(vector<off_t>& v, float& avg, float& var) 
-{
-  avg = 0.0;
-  for (int i=0; i<v.size(); i++)
-       avg += v[i];
-  avg /= v.size();
-  
-  var = 0.0;
-  for (int i=0; i<v.size(); i++)
-       var += (v[i] - avg) * (v[i] - avg);
-  var /= v.size();
-}
-
-
-void testpgs(int n, // numpg
-                        off_t pggb,
-                        float& avg,
-                        float& var,
-                        off_t& numo
-                        )
-{
-  off_t dist = (off_t)n * 1024LL*1024LL * (off_t)pggb;  //kb
-  vector<off_t> pgs(n);
-  off_t did = 0;
-  
-  no = 0;
-  while (did < dist) {
-       off_t s = get_object();
-       pgs[rand()%n] += s;
-       did += s;
-  }
-  while (!object_queue.empty())
-       pgs[rand()%n] += get_object();
-
-  numo = no;
-  //cout << did/n << endl; 
-
-  //for (int i=0; i<n; i++) cout << pgs[i] << endl;
-
-  getdist(pgs, avg, var);
-  //cout << "avg " << avg << "  var " << var << "  dev " << sqrt(var) << endl;
-}
-
-
-
-int main()
-{
-  /*
-
-// File Size 
-//cate   count_mean             size_mean       
-1b      -0.5     0.65434375     0        
-1k      0.5      19.0758125     0.00875          
-512K    1.5      35.6566        2.85875
-1M      2.5      27.7271875     25.0084375       
-2M      3.5      16.63503125    20.8046875       
-4M      4.5      106.82384375   296.053125       
-8M      5.5      81.493375      335.77625        
-16M     6.5      14.13553125    185.9775         
-32M     7.5      2.176          52.921875
-256M    8.5      0.655938       47.8066
-512M    9.5      0.1480625      57.83375 
-2G      10.5     0.020125       19.2888 
-  */
-  file_size_distn.add(1, 19.0758125+0.65434375);
-  file_size_distn.add(512, 35.6566);
-  file_size_distn.add(1024, 27.7271875);
-  file_size_distn.add(2*1024, 16.63503125);
-  file_size_distn.add(4*1024, 106.82384375);
-  file_size_distn.add(8*1024, 81.493375);
-  file_size_distn.add(16*1024, 14.13553125);
-  file_size_distn.add(32*1024, 2.176);
-  file_size_distn.add(256*1024, 0.655938);
-  file_size_distn.add(512*1024, 0.1480625);
-  file_size_distn.add(1*1024*1024, 0.020125); // actually 2, but 32bit
-  file_size_distn.normalize();
-
-  
-  for (int pggb = 1; pggb < 16; pggb++) {
-       cout << pggb;
-       for (int max = 1; max <= 1024; max *= 2) {
-         float avg, var, var2, var3;
-         off_t no;
-         max_object_size = max*1024;
-         testpgs(100, pggb, avg, var, no);
-         testpgs(100, pggb, avg, var2, no);
-         testpgs(100, pggb, avg, var3, no);
-         float dev = sqrt((var+var2+var3)/3.0);
-         cout << "\t" << no << "\t" << max << "\t" << dev;
-       }
-       cout << endl;
-  }
-
-
-
-
-}
diff --git a/trunk/ceph/crush/test/smallbucket.cc b/trunk/ceph/crush/test/smallbucket.cc
deleted file mode 100644 (file)
index 1dbc19b..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-
-
-#include "../crush.h"
-using namespace crush;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-       b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       buckets[h].push_back(b);
-       return b;
-  } else {
-       // mixed
-       Bucket *b = new TreeBucket(h+1);
-       c.add_bucket(b);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, buckets, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-         n->set_parent(b->get_id());
-       }
-       buckets[h].push_back(b);
-       //cout << b->get_id() << " mixedbucket with " << wid[h] << " at " << h << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, map< int, list<Bucket*> >& buckets, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, buckets, ndisks);
-  return b->get_id();
-}
-
-
-void place(Crush& c, Rule& rule, int numpg, int numrep, vector<int>& ocount)
-{
-  vector<int> v(numrep);
-  //map<int,int> ocount;
-
-  for (int x=1; x<=numpg; x++) {
-       
-       //cout << H(x) << "\t" << h(x) << endl;
-       c.do_rule(rule, x, v);
-       //cout << "v = " << v << endl;// " " << v[0] << " " << v[1] << "  " << v[2] << endl;
-       
-       bool bad = false;
-       for (int i=0; i<numrep; i++) {
-         //int d = b.choose_r(x, i, h);
-         //v[i] = d;
-         ocount[v[i]]++;
-         for (int j=i+1; j<numrep; j++) {
-               if (v[i] == v[j]) 
-                 bad = true;
-         }
-       }
-       if (bad)
-         cout << "bad set " << x << ": " << v << endl;
-       
-       //placement[x] = v;
-
-       //cout << v << "\t" << ocount << endl;
-  }
-  
-
-}
-
-
-int main()//float testmovement(int depth, int branching, int udisks)
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-  
-  vector<int> wid;
-  wid.push_back(10);
-  wid.push_back(2);
-
-  map< int, list<Bucket*> > buckets;
-  root = make_hierarchy(c, wid, buckets, ndisks);
-
-  // add small bucket
-  vector<int> disks;
-  for (int i=0; i<3; i++)
-       disks.push_back(ndisks++);
-  UniformBucket *b = new UniformBucket(1, 0, 1, disks);
-  b->make_primes(h);
-  Bucket *o = buckets[1].back();
-  c.add_bucket(b);
-  //cout << " adding under " << o->get_id() << endl;
-  c.add_item(o->get_id(), b->get_id(), b->get_weight());
-  
-
-  // rule
-  int numrep = 6;
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-  //c.overload[10] = .1;
-
-  int pg_per = 10000;
-  int numpg = pg_per*ndisks/numrep;
-  
-  vector<int> ocount(ndisks);
-
-  c.print(cout, root);
-
-  place(c, rule, numpg, numrep, ocount);
-  
-  for (int i=0; i<ocount.size(); i++) {
-       cout << "disk " << i << " = " << ocount[i] << endl;
-  }
-
-  return 0;
-}
-
-
diff --git a/trunk/ceph/crush/test/speed_bucket.cc b/trunk/ceph/crush/test/speed_bucket.cc
deleted file mode 100644 (file)
index 973379f..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int numrep = 1;
-
-
-double go(int n, int bucket) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  Bucket *b;
-  vector<int> items;
-  if (bucket == 0) b = new UniformBucket(1,0,10,items);
-  if (bucket == 1) b = new TreeBucket(1);
-  if (bucket == 2) b = new ListBucket(1);
-  if (bucket == 3) b = new StrawBucket(1);
-
-  for (int d=0; d<n; d++)
-       b->add_item(ndisks++, 1);
-
-  //if (!bucket)       ((UniformBucket*)b)->make_primes(h);
-
-  root = c.add_bucket(b);
-
-  // rule
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
-  int place = 1000000;
-
-
-  vector<int> v(numrep);
-  set<int> out;
-  map<int,float> overload;
-
-  utime_t start = g_clock.now();
-
-  for (int x=1; x <= place; x++)
-       c.do_rule(rule, x, v, out, overload);
-
-  utime_t end = g_clock.now();
-
-  end -= start;
-  double el = (double)end;
-
-  //cout << "\t" << ndisks;
-
-  return el;
-}
-
-
-int main() 
-{
-
-  for (int n=4; n<=50; n += 4) {
-       cout << n;
-       for (int b=0; b<4; b++) {
-         double el = go(n,b);
-         cout << "\t" << el;
-       }
-       cout << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/speed_depth.cc b/trunk/ceph/crush/test/speed_depth.cc
deleted file mode 100644 (file)
index 32275d1..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int uniform = 10;
-int branching = 10;
-int buckettype = 0;
-int numrep = 1;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b;
-       if (buckettype == 0)
-         b = new TreeBucket(h+1);
-       else if (buckettype == 1 || buckettype == 2)
-         b = new ListBucket(h+1);
-       else if (buckettype == 3)
-         b = new StrawBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-double go(int dep, int per) 
-{
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  if (1) {
-       wid.push_back(uniform);
-       for (int d=1; d<dep; d++)
-         wid.push_back(per);
-  }
-  if (0) {
-       if (dep == 0) 
-         wid.push_back(1000);
-       if (dep == 1) {
-         wid.push_back(1);
-         wid.push_back(1000);
-       }
-       if (dep == 2) {
-         wid.push_back(5);
-         wid.push_back(5);
-         wid.push_back(8);
-         wid.push_back(5);
-       }       
-  }
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  
-
-
-  // rule
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
-  int place = 1000000;
-
-
-  vector<int> v(numrep);
-
-  utime_t start = g_clock.now();
-
-  set<int> out;
-  map<int,float> overload;
-
-  for (int x=1; x <= place; x++)
-       c.do_rule(rule, x, v, out, overload);
-
-  utime_t end = g_clock.now();
-
-  end -= start;
-  double el = (double)end;
-
-  //cout << "\t" << ndisks;
-
-  return el;
-}
-
-
-int main() 
-{
-  uniform = branching = 8;
-
-  cout << "// dep\tuniform\tbranch\tndisks" << endl;
-
-  for (int d=2; d<=5; d++) {
-       cout << d;// << "\t" << branching;
-       cout << "\t" << uniform;
-       cout << "\t" << branching;
-
-       int n = 1;
-       for (int i=0; i<d; i++)
-         n *= branching;
-       cout << "\t" << n;
-
-       numrep = 2;
-
-       // crush
-       for (buckettype = 0; buckettype <= 3; buckettype++) {
-         switch (buckettype) {
-         case 0: cout << "\ttree"; break;
-         case 1: cout << "\tlist"; break;
-         case 2: continue;
-         case 3: cout << "\tstraw"; break;
-         }
-
-         //for (numrep = 1; numrep <= 3; numrep++) {
-         //cout << "\t" << numrep;
-         
-         double el = go(d, branching);
-         cout << "\t" << el;
-       }
-
-       // rush
-
-       buckettype = 0;
-       cout << "\trush_T\t" << go(2, n/uniform);
-
-       buckettype = 1;
-       cout << "\trush_P\t" << go(2, n/uniform);
-
-       cout << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/speed_rush.cc b/trunk/ceph/crush/test/speed_rush.cc
deleted file mode 100644 (file)
index 93a5584..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int branching = 10;
-bool linear = false;
-int numrep = 1;
-
-Bucket *make_bucket(Crush& c, vector<int>& wid, int h, int& ndisks)
-{
-  if (h == 0) {
-       // uniform
-       Hash hash(123);
-       vector<int> disks;
-       for (int i=0; i<wid[h]; i++)
-         disks.push_back(ndisks++);
-       UniformBucket *b = new UniformBucket(1, 0, 10, disks);
-       //b->make_primes(hash);  
-       c.add_bucket(b);
-       //cout << h << " uniformbucket with " << wid[h] << " disks" << endl;
-       return b;
-  } else {
-       // mixed
-       Bucket *b;
-       if (linear)
-         b = new ListBucket(h+1);
-       else
-         b = new TreeBucket(h+1);
-       for (int i=0; i<wid[h]; i++) {
-         Bucket *n = make_bucket(c, wid, h-1, ndisks);
-         b->add_item(n->get_id(), n->get_weight());
-       }
-       c.add_bucket(b);
-       //cout << h << " mixedbucket with " << wid[h] << endl;
-       return b;
-  }
-}
-
-int make_hierarchy(Crush& c, vector<int>& wid, int& ndisks)
-{
-  Bucket *b = make_bucket(c, wid, wid.size()-1, ndisks);
-  return b->get_id();
-}
-
-
-double go(int s) 
-{
-  int dep = 2;
-  Hash h(73232313);
-
-  // crush
-  Crush c;
-
-
-  // buckets
-  int root = -1;
-  int ndisks = 0;
-
-  vector<int> wid;
-  if (1) {
-       //for (int d=0; d<dep; d++)
-       wid.push_back(8);
-       wid.push_back(s/8);
-  }
-  if (0) {
-       if (dep == 0) 
-         wid.push_back(1000);
-       if (dep == 1) {
-         wid.push_back(1);
-         wid.push_back(1000);
-       }
-       if (dep == 2) {
-         wid.push_back(5);
-         wid.push_back(5);
-         wid.push_back(8);
-         wid.push_back(5);
-       }       
-  }
-
-  if (1) {
-       root = make_hierarchy(c, wid, ndisks);
-  }
-  
-
-
-  // rule
-  Rule rule;
-  rule.steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, numrep, 0));
-  rule.steps.push_back(RuleStep(CRUSH_RULE_EMIT));
-
-
-  int place = 1000000;
-
-
-  vector<int> v(numrep);
-
-  utime_t start = g_clock.now();
-
-  for (int x=1; x <= place; x++)
-       c.do_rule(rule, x, v);
-
-  utime_t end = g_clock.now();
-
-  end -= start;
-  double el = (double)end;
-
-  cout << "\t" << ndisks;
-
-  return el;
-}
-
-
-int main() 
-{
-  branching = 8;
-
-  int d = 2;
-  numrep = 2;
-
-  for (int s = 64; s <= 32768; s *= 8) {
-       cout << "t";
-       linear = false;
-       double el = go(s, d);
-       cout << "\t" << el;
-
-       cout << "\tp";
-       linear = true;
-       el = go(s, d);
-       cout << "\t" << el;
-
-       cout << endl;
-  }
-}
diff --git a/trunk/ceph/crush/test/t.cc b/trunk/ceph/crush/test/t.cc
deleted file mode 100644 (file)
index 0785ef4..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-
-#include "../../common/Clock.h"
-#include "../crush.h"
-using namespace crush;
-
-
-Clock g_clock;
-
-#include <math.h>
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-int branching = 10;
-bool linear = false;
-int numrep = 1;
-
-int main() {
-
-  Bucket *b = new UniformBucket(1, 0);
-  //b = new TreeBucket(1);
-}
-
diff --git a/trunk/ceph/crush/test/testbucket.cc b/trunk/ceph/crush/test/testbucket.cc
deleted file mode 100644 (file)
index 065721c..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-
-
-#include "../Bucket.h"
-using namespace crush;
-
-#include <iostream>
-#include <vector>
-using namespace std;
-
-
-ostream& operator<<(ostream& out, vector<int>& v)
-{
-  out << "[";
-  for (int i=0; i<v.size(); i++) {
-       if (i) out << " ";
-       out << v[i];
-  }
-  out << "]";
-  return out;
-}
-
-
-int main() 
-{
-  Hash h(73);
-
-  int ndisks = 0;
-  int numrep = 3;
-
-  StrawBucket mb(1);
-  /*for (int i=0;i<10;i++)
-       mb.add_item(ndisks++, 10);
-  */
-  mb.add_item(ndisks++, 1);
-  mb.add_item(ndisks++, 1);
-  mb.add_item(ndisks++, 10);
-  mb.add_item(ndisks++, 10);
-  mb.add_item(ndisks++, 100);
-  mb.add_item(ndisks++, 1000);
-
-  vector<int> ocount(ndisks);
-
-  vector<int> v(numrep);
-  int nplace = 0;
-  for (int x=1; x<1000000; x++) {
-       //cout << H(x) << "\t" << h(x) << endl;
-       for (int i=0; i<numrep; i++) {
-         int d = mb.choose_r(x, i, h);
-         v[i] = d;
-         ocount[d]++;
-         nplace++;
-       }
-       //cout << v << "\t" << endl;//ocount << endl;
-  }
-
-  for (int i=0; i<ocount.size(); i++) {
-       float f = ocount[i] / (float)nplace;
-       cout << "disk " << i << " has " << ocount[i] << "  " << f << endl;
-  }
-
-}
diff --git a/trunk/ceph/crush/test/testnormal.cc b/trunk/ceph/crush/test/testnormal.cc
deleted file mode 100644 (file)
index 17c8cbf..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-
-#include <vector>
-#include <iostream>
-using namespace std;
-
-
-void getdist(vector<int>& v, float& avg, float& var) 
-{
-  avg = 0.0;
-  for (int i=0; i<v.size(); i++)
-       avg += v[i];
-  avg /= v.size();
-  
-  var = 0.0;
-  for (int i=0; i<v.size(); i++)
-       var += (v[i] - avg) * (v[i] - avg);
-  var /= v.size();
-}
-
-int main() 
-{
-  int n = 50;
-  vector<int> a(n);
-  vector<int> b(n);
-
-  for (int i=0; i<n*n; i++)
-       a[rand()%n]++;
-
-  float aavg, avar;
-  getdist(a, aavg, avar);
-
-  for (int i=0; i<7*n*n; i++)
-       b[rand()%n]++;
-
-  float bavg, bvar;
-  getdist(b, bavg, bvar);
-
-  cout << "a avg " << aavg << " var " << avar << endl;
-  cout << "b avg " << bavg << " var " << bvar << endl;
-
-
-  vector<int> c(n);
-  for (int i=0; i<n; i++)
-       c[i] = a[i] * b[i];
-
-  float cavg, cvar;
-  getdist(c, cavg, cvar);
-
-  cout << "c avg " << cavg << " var " << cvar << endl;
-       
-}
diff --git a/trunk/ceph/crush/types.h b/trunk/ceph/crush/types.h
new file mode 100644 (file)
index 0000000..ffb208b
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _CRUSH_TYPES_H
+#define _CRUSH_TYPES_H
+
+#ifdef KERNEL
+# define free(x) kfree(x)
+#else
+# include <stdlib.h>
+#endif
+
+
+#include <linux/types.h>  /* just for int types */
+
+#ifndef BUG_ON
+# include <assert.h>
+# define BUG_ON(x) assert(!(x))
+#endif
+
+#endif
diff --git a/trunk/ceph/crush2/Makefile b/trunk/ceph/crush2/Makefile
deleted file mode 100644 (file)
index 6a9bae0..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
-CC = gcc
-CFLAGS = -Wall
-CFLAGS += -O3 -g
-LD = ld
-RM = rm
-
-all: depend builder.o libcrush.o
-
-clean:
-       rm -f *.o libcrush.o
-
-%.o: %.c
-       ${CC} ${CFLAGS} -c $< -o $@
-
-libcrush.o: crush.o buckets.o
-       $(LD) -i -o $@ $^
-
-.depend:
-       touch .depend
-
-depend:
-       $(RM) .depend
-       makedepend -f- -- $(CFLAGS) -- *.c > .depend 2>/dev/null
-
-include .depend
diff --git a/trunk/ceph/crush2/buckets.c b/trunk/ceph/crush2/buckets.c
deleted file mode 100644 (file)
index 557dc68..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-
-#include "hash.h"
-#include "buckets.h"
-
-int 
-crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r)
-{
-       unsigned o, p, s;
-       o = crush_hash32_2(x, bucket->h.id);
-       p = bucket->primes[crush_hash32_2(bucket->h.id, x) % bucket->h.size];
-       s = (x + o + (r+1)*p) % bucket->h.size;
-       return bucket->h.items[s];
-}
-
-int 
-crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r)
-{
-       int i;
-       __u64 w;
-       
-       for (i=0; i<bucket->h.size; i++) {
-               w = crush_hash32_4(x, bucket->h.items[i], r, bucket->h.id) & 0xffff;
-               w = (w * bucket->sum_weights[i]) >> 32;
-               if (w < bucket->item_weights[i])
-                       return bucket->h.items[i];
-       }
-       
-       BUG_ON(1);
-       return 0;
-}
-
-int 
-crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r)
-{
-       return 0;
-}
-
-int 
-crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r)
-{
-       int i;
-       int high = 0;
-       unsigned high_draw = 0;
-       __u64 draw;
-       
-       for (i=0; i<bucket->h.size; i++) {
-               draw = (crush_hash32_3(x, bucket->h.items[i], r) & 0xffff) * bucket->straws[i];
-               draw = draw >> 32;
-               if (i == 0 || draw > high_draw) {
-                       high = i;
-                       high_draw = draw;
-               }
-       }
-       
-       return high;
-}
-
-
-
-void crush_destroy_bucket_uniform(struct crush_bucket_uniform *b)
-{
-       free(b->primes);
-       free(b->h.items);
-}
-
-void crush_destroy_bucket_list(struct crush_bucket_list *b)
-{
-       free(b->item_weights);
-       free(b->sum_weights);
-       free(b->h.items);
-}
-
-void crush_destroy_bucket_tree(struct crush_bucket_tree *b)
-{
-       free(b->h.items);
-}
-
-void crush_destroy_bucket_straw(struct crush_bucket_straw *b)
-{
-       free(b->straws);
-       free(b->h.items);
-}
diff --git a/trunk/ceph/crush2/buckets.h b/trunk/ceph/crush2/buckets.h
deleted file mode 100644 (file)
index aab536b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef _CRUSH_BUCKETS_H
-#define _CRUSH_BUCKETS_H
-
-#include "types.h"
-
-enum {
-       CRUSH_BUCKET_UNIFORM = 1,
-       CRUSH_BUCKET_LIST = 2,
-       CRUSH_BUCKET_TREE = 3,
-       CRUSH_BUCKET_STRAW = 4
-};
-
-struct crush_bucket {
-       __u32 id;
-       __u32 type;
-       __u32 weight;    /* 16-bit fixed point */
-       __u32 size;      /* num items */
-       __s32 *items;
-};
-
-struct crush_bucket_uniform {
-       struct crush_bucket h;
-       __u32 item_weight;  /* 16-bit fixed point */
-       __u32 *primes;
-};
-
-struct crush_bucket_list {
-       struct crush_bucket h;
-       __u32 *item_weights;  /* 16-bit fixed point */
-       __u32 *sum_weights;   /* 16-bit fixed point.  element i is sum of weights 0..i, inclusive */
-};
-
-struct crush_bucket_tree {
-       struct crush_bucket h;
-       
-};
-
-struct crush_bucket_straw {
-       struct crush_bucket h;
-       __u32 *straws;  /* 16-bit fixed point */
-};
-
-extern int crush_bucket_uniform_choose(struct crush_bucket_uniform *bucket, int x, int r);
-extern int crush_bucket_list_choose(struct crush_bucket_list *bucket, int x, int r);
-extern int crush_bucket_tree_choose(struct crush_bucket_tree *bucket, int x, int r);
-extern int crush_bucket_straw_choose(struct crush_bucket_straw *bucket, int x, int r);
-
-extern void crush_destroy_bucket_uniform(struct crush_bucket_uniform *);
-extern void crush_destroy_bucket_list(struct crush_bucket_list *);
-extern void crush_destroy_bucket_tree(struct crush_bucket_tree *);
-extern void crush_destroy_bucket_straw(struct crush_bucket_straw *);
-
-#endif
diff --git a/trunk/ceph/crush2/builder.c b/trunk/ceph/crush2/builder.c
deleted file mode 100644 (file)
index 803eb9d..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-
-#include <string.h>
-#include <math.h>
-#include <stdlib.h>
-
-#include "builder.h"
-#include "hash.h"
-
-
-struct crush_map *crush_new()
-{
-       struct crush_map *m;
-       m = malloc(sizeof(*m));
-       memset(&m, 0, sizeof(m));
-       return m;
-}
-
-/*
- * finalize should be called _after_ all buckets are added to the map.
- */
-void crush_finalize(struct crush_map *map)
-{
-       int b, i, c;
-       
-       /* calc max_devices */
-       for (b=0; b<map->max_buckets; b++) {
-               if (map->buckets[b] == 0) continue;
-               for (i=0; i<map->buckets[b]->size; i++) 
-                       if (map->buckets[b]->items[i] > map->max_devices)
-                               map->max_devices = map->buckets[b]->items[i];
-       }
-       
-       /* allocate arrays */
-       map->device_parents = malloc(sizeof(map->device_parents[0]) * map->max_devices);
-       map->device_offload = malloc(sizeof(map->device_offload[0]) * map->max_devices);
-       memset(map->device_parents, 0, sizeof(map->device_parents[0]) * map->max_devices);
-       memset(map->device_offload, 0, sizeof(map->device_offload[0]) * map->max_devices);
-       map->bucket_parents = malloc(sizeof(map->bucket_parents[0]) * map->max_buckets);
-       memset(map->bucket_parents, 0, sizeof(map->bucket_parents[0]) * map->max_buckets);
-       
-       /* build reverse map */
-       for (b=0; b<map->max_buckets; b++) {
-               if (map->buckets[b] == 0) continue;
-               for (i=0; i<map->buckets[b]->size; i++) {
-                       c = map->buckets[b]->items[i];
-                       if (c >= 0)
-                               map->device_parents[c] = map->buckets[b]->id;
-                       else
-                               map->bucket_parents[-c] = map->buckets[b]->id;
-               }
-       }
-}
-
-/* 
- * deallocate
- */
-void crush_destroy(struct crush_map *map)
-{
-       int b;
-       
-       /* buckets */
-       for (b=0; b<map->max_buckets; b++) {
-               if (map->buckets[b] == 0) continue;
-               switch (map->buckets[b]->type) {
-               case CRUSH_BUCKET_UNIFORM:
-                       crush_destroy_bucket_uniform((struct crush_bucket_uniform*)map->buckets[b]);
-                       break;
-               case CRUSH_BUCKET_LIST:
-                       crush_destroy_bucket_list((struct crush_bucket_list*)map->buckets[b]);
-                       break;
-               case CRUSH_BUCKET_TREE:
-                       crush_destroy_bucket_tree((struct crush_bucket_tree*)map->buckets[b]);
-                       break;
-               case CRUSH_BUCKET_STRAW:
-                       crush_destroy_bucket_straw((struct crush_bucket_straw*)map->buckets[b]);
-                       break;
-               }
-       }
-       free(map->buckets);
-       
-       /* rules */
-       for (b=0; b<map->max_rules; b++) {
-               if (map->rules[b] == 0) continue;
-               if (map->rules[b]->steps)
-                       free(map->rules[b]->steps);
-               free(map->rules[b]);
-       }
-       free(map->rules);
-       
-       free(map->bucket_parents);
-       free(map->device_parents);
-       free(map->device_offload);
-       
-       memset(map, 0, sizeof(*map));
-}
-
-
-
-
-/** rules **/
-
-int crush_add_rule(struct crush_map *map,
-                  struct crush_rule *rule)
-{
-       int id;
-       
-       /* find a rule id */
-       for (id=0; id < map->max_rules; id++)
-               if (map->rules[id] == 0) break;
-       if (id == map->max_rules) {
-               /* expand array */
-               if (map->max_rules)
-                       map->max_rules *= 2;
-               else
-                       map->max_rules = 8;
-               map->rules = realloc(map->rules, map->max_rules * sizeof(map->rules[0]));
-       }
-       
-       /* add it */
-       map->rules[id] = rule;
-       return id;
-}
-
-struct crush_rule *crush_make_rule()
-{
-       struct crush_rule *rule;
-       
-       rule = malloc(sizeof(struct crush_rule));
-       memset(&rule, 0, sizeof(rule));
-       return rule;
-}
-
-void crush_rule_add_step(struct crush_rule *rule, int op, int arg1, int arg2)
-{
-       rule->len++;
-       if (rule->steps)
-               rule->steps = malloc(sizeof(rule->steps[0])*rule->len);
-       else
-               rule->steps = realloc(rule->steps, sizeof(rule->steps[0])*rule->len);
-       rule->steps[rule->len-1].op = op;
-       rule->steps[rule->len-1].arg1 = arg1;
-       rule->steps[rule->len-1].arg2 = arg2;
-}
-
-
-/** buckets **/
-
-int crush_add_bucket(struct crush_map *map,
-                    struct crush_bucket *bucket)
-{
-       int id;
-       
-       /* find a bucket id */
-       for (id=0; id < map->max_buckets; id++)
-               if (map->buckets[id] == 0) break;
-       if (id == map->max_buckets) {
-               /* expand array */
-               if (map->max_buckets)
-                       map->max_buckets *= 2;
-               else
-                       map->max_buckets = 8;
-               map->buckets = realloc(map->buckets, map->max_buckets * sizeof(map->buckets[0]));
-       }
-       
-       /* add it */
-       bucket->id = id;
-       map->buckets[id] = bucket;
-       return id;
-}
-
-
-void crush_make_uniform_bucket(struct crush_map *map,
-                              struct crush_bucket_uniform *bucket,
-                              int size,
-                              int *items,
-                              int item_weight)
-{
-       int i, j, x;
-       
-       memset(bucket, 0, sizeof(*bucket));
-       bucket->h.size = size;
-       bucket->h.weight = size * item_weight;
-       
-       bucket->item_weight = item_weight;
-       
-       bucket->h.items = malloc(sizeof(__u32)*size);
-       for (i=0; i<size; i++)
-               bucket->h.items[i] = items[i];
-       
-       /* generate some primes */
-       bucket->primes = malloc(sizeof(__u32)*size);
-
-       x = size + 1;
-       x += crush_hash32(size) % (3*size);  /* make it big */
-       x |= 1;                              /* and odd */
-       
-       i=0;
-       while (i < size) {
-               for (j=2; j*j <= x; j++) 
-                       if (x % j == 0) break;
-               if (j*j > x) 
-                       bucket->primes[i++] = x;
-               x += 2;
-       }
-}
-
-void crush_make_list_bucket(struct crush_map *map,
-                           struct crush_bucket_list *bucket,
-                           int size,
-                           int *items,
-                           int *weights)
-{
-       int i;
-       int w;
-       
-       memset(bucket, 0, sizeof(*bucket));
-       bucket->h.size = size;
-       
-       bucket->h.items = malloc(sizeof(__u32)*size);
-       bucket->item_weights = malloc(sizeof(__u32)*size);
-       bucket->sum_weights = malloc(sizeof(__u32)*size);
-       w = 0;
-       for (i=0; i<size; i++) {
-               bucket->h.items[i] = items[i];
-               bucket->item_weights[i] = weights[i];
-               w += weights[i];
-               bucket->sum_weights[i] = w;
-       }
-       
-       bucket->h.weight = w;
-}
-
-
-void crush_make_straw_bucket(struct crush_map *map,
-                            struct crush_bucket_straw *bucket,
-                            int size,
-                            int *items,
-                            int *weights)
-{
-       int *reverse;
-       int i, j, k;
-       
-       double straw, wbelow, lastw, wnext, pbelow;
-       int numleft;
-       
-       memset(bucket, 0, sizeof(*bucket));
-       bucket->h.size = size;
-       
-       bucket->h.items = malloc(sizeof(__u32)*size);
-       bucket->straws = malloc(sizeof(__u32)*size);
-       
-       bucket->h.weight = 0;
-       for (i=0; i<size; i++) {
-               bucket->h.items[i] = items[i];
-               bucket->h.weight += weights[i];
-       }
-       
-       /* reverse sort by weight */
-       reverse = malloc(sizeof(int) * size);
-       reverse[0] = items[0];
-       for (i=1; i<size; i++) {
-               for (j=0; j<i; j++) {
-                       if (weights[i] < weights[reverse[j]]) {
-                               /* insert here */
-                               for (k=i; k>j; k--)
-                                       reverse[k] = reverse[k-1];
-                               reverse[j] = items[i];
-                       }
-               }
-               if (j == i)
-                       reverse[i] = items[i];
-       }
-       
-       numleft = size;
-       straw = 1.0;
-       wbelow = 0;
-       lastw = 0;
-       
-       i=0;
-       while (i < size) {
-               /* set this item's straw */
-               bucket->straws[reverse[i]] = straw * 0x10000;
-               i++;
-               if (i == size) break;
-               
-               /* same weight as previous? */
-               if (weights[reverse[i]] == weights[reverse[i-1]]) 
-                       continue;
-               
-               /* adjust straw for next guy */
-               wbelow += (((double)weights[reverse[i-1]] / (double)0x10000) - lastw) * numleft;
-               numleft--;
-               wnext = numleft * ((double)(weights[reverse[i]] - weights[reverse[i-1]]) / (double)0x10000);
-               pbelow = wbelow / (wbelow + wnext);
-               
-               straw *= pow((double)1.0 / pbelow, (double)1.0 / numleft);
-               
-               lastw = weights[reverse[i-1]];
-       }
-       
-       free(reverse);
-       
-}
-
diff --git a/trunk/ceph/crush2/crush.c b/trunk/ceph/crush2/crush.c
deleted file mode 100644 (file)
index 1c06ca7..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-
-#include "crush.h"
-#include "hash.h"
-
-/*
- * choose numrep distinct items of given type
- */
-static int crush_choose(struct crush_map *map,
-                       struct crush_bucket *bucket,
-                       int x, int numrep, int type,
-                       int *out, int firstn)
-{
-       int rep;
-       int ftotal, flocal;
-       int retry_rep, skip_rep;
-       struct crush_bucket *in = bucket;
-       int r;
-       int i;
-       int item;
-       int itemtype;
-       int outpos;
-       int collide, bad;
-       
-       outpos = 0;
-       
-       for (rep = 0; rep < numrep; rep++) {
-               /* keep trying until we get a non-out, non-colliding item */
-               ftotal = 0;
-               skip_rep = 0;
-               
-               while (1) {
-                       in = bucket;               /* initial bucket */
-                       
-                       /* choose through intervening buckets */
-                       flocal = 0;
-                       retry_rep = 0;
-                       
-                       while (1) {
-                               r = rep;
-                               if (in->type == CRUSH_BUCKET_UNIFORM) {
-                                       /* be careful */
-                                       if (firstn || numrep >= in->size) {
-                                               r += ftotal;           /* r' = r + f_total */
-                                       } else {
-                                               r += numrep * flocal;  /* r' = r + n*f_local */
-                                               /* make sure numrep is not a multiple of bucket size */
-                                               if (in->size % numrep == 0)
-                                                       /* shift seq once per pass through the bucket */
-                                                       r += numrep * flocal / in->size;  
-                                       }
-                               } else {
-                                       if (firstn) 
-                                               r += ftotal;           /* r' = r + f_total */
-                                       else 
-                                               r += numrep * flocal;  /* r' = r + n*f_local */
-                               }
-
-                               /* bucket choose */
-                               switch (in->type) {
-                               case CRUSH_BUCKET_UNIFORM:
-                                       item = crush_bucket_uniform_choose((struct crush_bucket_uniform*)in, x, r);
-                                       break;
-                               case CRUSH_BUCKET_LIST:
-                                       item = crush_bucket_list_choose((struct crush_bucket_list*)in, x, r);
-                                       break;
-                               case CRUSH_BUCKET_TREE:
-                                       item = crush_bucket_tree_choose((struct crush_bucket_tree*)in, x, r);
-                                       break;
-                               case CRUSH_BUCKET_STRAW:
-                                       item = crush_bucket_straw_choose((struct crush_bucket_straw*)in, x, r);
-                                       break;
-                               default:
-                                       BUG_ON(1);
-                               }
-                               
-                               /* desired type? */
-                               if (item < 0) 
-                                       itemtype = map->buckets[-item]->type;
-                               else 
-                                       itemtype = 0;
-                               
-                               /* keep going? */
-                               if (itemtype != type) {
-                                       in = map->buckets[-item];
-                                       continue;
-                               }
-                               
-                               /* collision? */
-                               collide = 0;
-                               for (i=0; i<rep; i++) {
-                                       if (out[i] == item) {
-                                               collide = 1;
-                                               break;
-                                       }
-                               }
-                               
-                               /* bad (out)? */
-                               bad = 0;
-                               if (itemtype == 0 && map->device_offload[item]) {
-                                       if (map->device_offload[item] >= 0x10000) 
-                                               bad = 1;
-                                       else if ((crush_hash32_2(x, item) & 0xffff) < map->device_offload[item])
-                                               bad = 1;
-                               }
-                               
-                               if (bad || collide) {
-                                       ftotal++;
-                                       flocal++;
-                                       
-                                       if (collide && flocal < 3) 
-                                               continue;   /* locally a few times */
-                                       if (ftotal >= 10) {
-                                               /* give up, ignore dup, fixme */
-                                               skip_rep = 1;
-                                               break;
-                                       }
-                                       retry_rep = 1;
-                               }
-                               break;
-                       }
-                       
-                       if (retry_rep) continue;
-               }
-               
-               if (skip_rep) continue;
-               
-               out[outpos] = item;
-               outpos++;
-       }
-       
-       return outpos;
-}
-
-
-int crush_do_rule(struct crush_map *map,
-                 int ruleno,
-                 int x, int *result, int result_max,
-                 int forcefeed)    /* -1 for none */
-{
-       int result_len;
-       int force_stack[CRUSH_MAX_DEPTH];
-       int force_pos = -1;
-       int a[CRUSH_MAX_SET];
-       int b[CRUSH_MAX_SET];
-       int *w;
-       int wsize = 0;
-       int *o;
-       int osize;
-       int *tmp;
-       struct crush_rule *rule;
-       int step;
-       int i;
-       int numrep;
-       
-       rule = map->rules[ruleno];
-       result_len = 0;
-       w = a;
-       o = b;
-       
-       /* determine hierarchical context of forcefeed, if any */
-       if (forcefeed >= 0) {
-               while (1) {
-                       force_stack[++force_pos] = forcefeed;
-                       if (forcefeed >= 0)
-                               forcefeed = map->device_parents[forcefeed];
-                       else
-                               forcefeed = map->bucket_parents[-forcefeed];
-                       if (forcefeed == 0) break;
-               }
-       }
-       
-       for (step = 0; step < rule->len; step++) {
-               switch (rule->steps[step].op) {
-               case CRUSH_RULE_TAKE:
-                       if (force_pos >= 0) {
-                               w[0] = force_stack[force_pos];
-                               force_pos--;
-                               BUG_ON(w[0] != rule->steps[step].arg1);
-                       } else {
-                               w[0] = rule->steps[step].arg1;
-                       }
-                       wsize = 1;
-                       break;
-                       
-               case CRUSH_RULE_CHOOSE_FIRSTN:
-               case CRUSH_RULE_CHOOSE_INDEP:
-                       BUG_ON(wsize == 0);
-                       
-                       /* reset output */
-                       osize = 0;
-                       
-                       for (i = 0; i < wsize; i++) {
-                               numrep = rule->steps[step].arg1;
-                               
-                               if (force_pos >= 0) {
-                                       o[osize++] = force_stack[force_pos];
-                                       force_pos--;
-                                       numrep--;
-                               }
-                               if (numrep)
-                                       crush_choose(map,
-                                                    map->buckets[-w[i]],
-                                                    x, numrep, rule->steps[step].arg2,
-                                                    o+osize, rule->steps[step].op == CRUSH_RULE_CHOOSE_FIRSTN);
-                       }
-                       
-                       /* swap t and w arrays */
-                       tmp = o;
-                       o = w;
-                       w = o;
-                       wsize = osize;
-                       break;      
-                       
-                       
-               case CRUSH_RULE_EMIT:
-                       for (i=0; i<wsize && result_max; i++) {
-                               result[result_len] = w[i];
-                               result_len++;
-                               result_max--;
-                       }
-                       wsize = 0;
-                       break;
-                       
-               default:
-                       BUG_ON(1);
-               }
-       }
-       
-       return result_len;
-}
-
diff --git a/trunk/ceph/crush2/crush.h b/trunk/ceph/crush2/crush.h
deleted file mode 100644 (file)
index 9dd5a00..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef _CRUSH_CRUSH_H
-#define _CRUSH_CRUSH_H
-
-#include "types.h"
-#include "buckets.h"
-
-enum {
-       CRUSH_RULE_TAKE,
-       CRUSH_RULE_CHOOSE_FIRSTN,
-       CRUSH_RULE_CHOOSE_INDEP,
-       CRUSH_RULE_EMIT
-};
-
-#define CRUSH_MAX_DEPTH 10
-#define CRUSH_MAX_SET   10
-
-struct crush_rule_step {
-       __u32 op;
-       __s32 arg1;
-       __s32 arg2;
-};
-
-struct crush_rule {
-       __u32 len;
-       struct crush_rule_step *steps;
-};
-
-struct crush_map {
-       struct crush_bucket **buckets;
-       struct crush_rule **rules;
-       
-       /* parent pointers */
-       __u32 *bucket_parents;
-       __u32 *device_parents;
-       
-       /* offload
-        * size max_devices, values 0...0xffff
-        *        0 == normal
-        *  0x10000 == 100% offload (i.e. failed)
-        */
-       __u32 *device_offload;   
-       
-       __u32 max_buckets;
-       __u32 max_rules;
-       __u32 max_devices;
-};
-
-extern int crush_do_rule(struct crush_map *map,
-                        int ruleno,
-                        int x, int *result, int result_max,
-                        int forcefeed); /* -1 for none */
-
-/*extern int crush_decode(struct crush_map *map, struct ceph_bufferlist *bl);*/
-
-#endif
diff --git a/trunk/ceph/crush2/hash.h b/trunk/ceph/crush2/hash.h
deleted file mode 100644 (file)
index 1ff4cca..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-#ifndef _CRUSH_HASH_H
-#define _CRUSH_HASH_H
-
-// Robert Jenkins' function for mixing 32-bit values
-// http://burtleburtle.net/bob/hash/evahash.html
-// a, b = random bits, c = input and output
-#define hashmix(a,b,c) \
-        a=a-b;  a=a-c;  a=a^(c>>13); \
-        b=b-c;  b=b-a;  b=b^(a<<8);  \
-        c=c-a;  c=c-b;  c=c^(b>>13); \
-        a=a-b;  a=a-c;  a=a^(c>>12); \
-        b=b-c;  b=b-a;  b=b^(a<<16); \
-        c=c-a;  c=c-b;  c=c^(b>>5);  \
-        a=a-b;  a=a-c;  a=a^(c>>3); \
-        b=b-c;  b=b-a;  b=b^(a<<10); \
-        c=c-a;  c=c-b;  c=c^(b>>15); 
-
-#define crush_hash_seed 1315423911
-
-static __inline__ unsigned crush_hash32(unsigned a) {
-       unsigned hash = crush_hash_seed ^ a;
-       unsigned b = a;
-       unsigned x = 231232;
-       unsigned y = 1232;
-       hashmix(b, x, hash);
-       hashmix(y, a, hash);
-       return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_2(unsigned a, unsigned b) {
-       unsigned hash = crush_hash_seed ^ a ^ b;
-       unsigned x = 231232;
-       unsigned y = 1232;
-       hashmix(a, b, hash);
-       hashmix(x, a, hash);
-       hashmix(b, y, hash);
-       return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_3(unsigned a, unsigned b, unsigned c) {
-       unsigned int hash = crush_hash_seed ^ a ^ b ^ c;
-       unsigned x = 231232;
-       unsigned y = 1232;
-       hashmix(a, b, hash);
-       hashmix(c, x, hash);
-       hashmix(y, a, hash);
-       hashmix(b, x, hash);
-       hashmix(y, c, hash);
-       return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_4(unsigned a, unsigned b, unsigned c, unsigned d) {
-       unsigned int hash = crush_hash_seed ^a ^ b ^ c ^ d;
-       unsigned x = 231232;
-       unsigned y = 1232;
-       hashmix(a, b, hash);
-       hashmix(c, d, hash);
-       hashmix(a, x, hash);
-       hashmix(y, b, hash);
-       hashmix(c, x, hash);
-       hashmix(y, d, hash);
-       return (hash & 0xFFFFFFFF);
-}
-
-static __inline__ unsigned crush_hash32_5(unsigned a, unsigned b, unsigned c, unsigned d, unsigned e) {
-       unsigned int hash = crush_hash_seed ^ a ^ b ^ c ^ d ^ e;
-       unsigned x = 231232;
-       unsigned y = 1232;
-       hashmix(a, b, hash);
-       hashmix(c, d, hash);
-       hashmix(e, x, hash);
-       hashmix(y, a, hash);
-       hashmix(b, x, hash);
-       hashmix(y, c, hash);
-       hashmix(d, x, hash);
-       hashmix(y, e, hash);
-       return (hash & 0xFFFFFFFF);
-}
-
-#endif
diff --git a/trunk/ceph/crush2/types.h b/trunk/ceph/crush2/types.h
deleted file mode 100644 (file)
index ffb208b..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef _CRUSH_TYPES_H
-#define _CRUSH_TYPES_H
-
-#ifdef KERNEL
-# define free(x) kfree(x)
-#else
-# include <stdlib.h>
-#endif
-
-
-#include <linux/types.h>  /* just for int types */
-
-#ifndef BUG_ON
-# include <assert.h>
-# define BUG_ON(x) assert(!(x))
-#endif
-
-#endif
index 200187510f698406225e5135cb252756cf44c93e..8c8fb91b2b18c4e86f881ab02b56bd547d5c14dd 100644 (file)
@@ -18,6 +18,8 @@
 
 #include "MonitorStore.h"
 
+#include "crush/CrushWrapper.h"
+
 #include "messages/MOSDFailure.h"
 #include "messages/MOSDMap.h"
 #include "messages/MOSDGetMap.h"
@@ -158,49 +160,55 @@ void OSDMonitor::create_initial()
 }
 
 
-void OSDMonitor::build_crush_map(Crush& crush,
+void OSDMonitor::build_crush_map(CrushWrapper& crush,
                                 map<int,double>& weights)
 {
+  // new
+  crush.create();
 
   if (g_conf.num_osd >= 12) {
     int ndom = g_conf.osd_max_rep;
-    UniformBucket *domain[ndom];
-    int domid[ndom];
-    for (int i=0; i<ndom; i++) {
-      domain[i] = new UniformBucket(1, 0);
-      domid[i] = crush.add_bucket(domain[i]);
-    }
-    
-    // add osds
+    int ritems[ndom];
+    int rweights[ndom];
+
     int nper = ((g_conf.num_osd - 1) / ndom) + 1;
     derr(0) << ndom << " failure domains, " << nper << " osds each" << dendl;
-    int i = 0;
-    for (int dom=0; dom<ndom; dom++) {
-      for (int j=0; j<nper; j++) {
-       domain[dom]->add_item(i, weights[i] ? weights[i]:1.0);
-       //derr(0) << "osd" << i << " in domain " << dom << dendl;
-       i++;
-       if (i == g_conf.num_osd) break;
+
+    int o = 0;
+    for (int i=0; i<ndom; i++) {
+      int items[nper];
+      //int w[nper];
+      int j;
+      rweights[i] = 0;
+      for (j=0; j<nper; j++, o++) {
+       if (o == g_conf.num_osd) break;
+       dout(20) << "added osd" << o << dendl;
+       items[j] = o;
+       //w[j] = weights[o] ? (0x10000 - (int)(weights[o] * 0x10000)):0x10000;
+       //rweights[i] += w[j];
+       rweights[i] += 0x10000;
       }
+
+      crush_bucket_uniform *domain = crush_make_uniform_bucket(1, j, items, 0x10000);
+      ritems[i] = crush_add_bucket(crush.map, (crush_bucket*)domain);
+      dout(20) << "added domain bucket i " << ritems[i] << " of size " << j << dendl;
     }
     
     // root
-    Bucket *root = new ListBucket(2);
-    for (int i=0; i<ndom; i++) {
-      //derr(0) << "dom " << i << " w " << domain[i]->get_weight() << dendl;
-      root->add_item(domid[i], domain[i]->get_weight());
-    }
-    int nroot = crush.add_bucket(root);    
+    crush_bucket_list *root = crush_make_list_bucket(2, ndom, ritems, rweights);
+    int rootid = crush_add_bucket(crush.map, (crush_bucket*)root);
     
     // rules
     // replication
     for (int i=1; i<=ndom; i++) {
-      int r = CRUSH_REP_RULE(i);
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_TAKE, nroot));
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, i, 1));
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, 1, 0));      
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+      crush_rule *rule = crush_make_rule();
+      crush_rule_add_step(rule, CRUSH_RULE_TAKE, rootid, 0);
+      crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, i, 1);
+      crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, 1, 0);
+      crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+      crush_add_rule(crush.map, CRUSH_REP_RULE(i), rule);
     }
+    /*
     // raid
     for (int i=g_conf.osd_min_raid_width; i <= g_conf.osd_max_raid_width; i++) {
       int r = CRUSH_RAID_RULE(i);      
@@ -215,6 +223,7 @@ void OSDMonitor::build_crush_map(Crush& crush,
        crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
       }
     }
+    */
     
     // test
     //vector<int> out;
@@ -222,20 +231,24 @@ void OSDMonitor::build_crush_map(Crush& crush,
     
   } else {
     // one bucket
-    Bucket *b = new UniformBucket(1, 0);
-    int root = crush.add_bucket(b);
-    for (int i=0; i<g_conf.num_osd; i++) {
-      b->add_item(i, weights[i] ? weights[i]:1.0);
-    }
+
+    int items[g_conf.num_osd];
+    for (int i=0; i<g_conf.num_osd; i++) 
+      items[i] = i;
+    
+    crush_bucket_uniform *b = crush_make_uniform_bucket(1, g_conf.num_osd, items, 0x10000);
+    int root = crush_add_bucket(crush.map, (crush_bucket*)b);
     
     // rules
     // replication
     for (int i=1; i<=g_conf.osd_max_rep; i++) {
-      int r = CRUSH_REP_RULE(i);
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_TAKE, root));
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE, i, 0));
-      crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
+      crush_rule *rule = crush_make_rule();
+      crush_rule_add_step(rule, CRUSH_RULE_TAKE, root, 0);
+      crush_rule_add_step(rule, CRUSH_RULE_CHOOSE_FIRSTN, i, 0);
+      crush_rule_add_step(rule, CRUSH_RULE_EMIT, 0, 0);
+      crush_add_rule(crush.map, CRUSH_REP_RULE(i), rule);
     }
+    /*
     // raid
     for (int i=g_conf.osd_min_raid_width; i <= g_conf.osd_max_raid_width; i++) {
       int r = CRUSH_RAID_RULE(i);      
@@ -243,7 +256,12 @@ void OSDMonitor::build_crush_map(Crush& crush,
       crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_CHOOSE_INDEP, i, 0));
       crush.rules[r].steps.push_back(RuleStep(CRUSH_RULE_EMIT));
     }
+    */
   }
+  crush.finalize();
+  dout(20) << "crush max_devices " << crush.map->max_devices << dendl;
+  //vector<int> t;
+  //crush.do_rule(2, 132, t, 4, -1);
 }
 
 
@@ -420,7 +438,7 @@ bool OSDMonitor::should_propose(double& delay)
     if (pending_inc.new_up.size() == osdmap.get_osds().size()) {
       delay = 0.0;
       if (g_conf.osd_auto_weight) {
-       Crush crush;
+       CrushWrapper crush;
        build_crush_map(crush, osd_weight);
        crush._encode(pending_inc.crush);
       }
index afdd625ae04aa18eaa641f12a52b83bdfed49fa9..c22c007f2d9b61bbd15eed1dd7fa39db7576df4c 100644 (file)
@@ -43,7 +43,7 @@ private:
 
   map<int,double> osd_weight;
 
-  void build_crush_map(Crush& crush,
+  void build_crush_map(CrushWrapper& crush,
                       map<int,double>& weights);
 
   // svc
index fda57d73ef99e9a16935c9f5b08b992465582573..2b476e04561686e0f785e1b2c103bbd0bfbdaa73 100644 (file)
@@ -28,8 +28,7 @@
 #include "common/Mutex.h"
 #include "common/Clock.h"
 
-#include "crush/crush.h"
-using namespace crush;
+#include "crush/CrushWrapper.h"
 
 #include <vector>
 #include <list>
@@ -144,7 +143,7 @@ private:
   map<int32_t,entity_inst_t> osd_inst;
 
  public:
-  Crush     crush;       // hierarchical map
+  CrushWrapper     crush;       // hierarchical map
 
   friend class OSDMonitor;
   friend class MDS;
@@ -207,9 +206,14 @@ private:
   
   void mark_down(int o, bool clean) { down_osds[o] = clean; }
   void mark_up(int o) { down_osds.erase(o); }
-  void mark_out(int o) { out_osds.insert(o); }
-  void mark_in(int o) { out_osds.erase(o); }
-
+  void mark_out(int o) { 
+    out_osds.insert(o); 
+    crush.update_offload_map(out_osds, overload_osds);
+  }
+  void mark_in(int o) { 
+    out_osds.erase(o); 
+    crush.update_offload_map(out_osds, overload_osds);
+  }
 
   void apply_incremental(Incremental &inc) {
     assert(inc.epoch == epoch+1);
@@ -223,8 +227,8 @@ private:
       return;
     }
     if (inc.crush.length()) {
-      int off = 0;
-      crush._decode(inc.crush, off);
+      bufferlist::iterator blp = inc.crush.begin();
+      crush._decode(blp);
     }
 
     // nope, incremental.
@@ -272,6 +276,8 @@ private:
          i++) {
       overload_osds[i->first] = i->second;
     }
+
+    crush.update_offload_map(out_osds, overload_osds);
   }
 
   // serialize, unserialize
@@ -288,7 +294,9 @@ private:
     ::_encode(overload_osds, blist);
     ::_encode(osd_inst, blist);
     
-    crush._encode(blist);
+    bufferlist cbl;
+    crush._encode(cbl);
+    ::_encode(cbl, blist);
   }
   
   void decode(bufferlist& blist) {
@@ -306,7 +314,12 @@ private:
     ::_decode(overload_osds, blist, off);
     ::_decode(osd_inst, blist, off);
     
-    crush._decode(blist, off);
+    bufferlist cbl;
+    ::_decode(cbl, blist, off);
+    bufferlist::iterator cblp = cbl.begin();
+    crush._decode(cblp);
+
+    crush.update_offload_map(out_osds, overload_osds);
   }
  
 
@@ -320,8 +333,6 @@ private:
   }
 
   ObjectLayout make_object_layout(object_t oid, int pg_type, int pg_size, int preferred=-1, int object_stripe_unit = 0) {
-    static crush::Hash H(777);
-
     int num = preferred >= 0 ? localized_pg_num:pg_num;
     int num_mask = preferred >= 0 ? localized_pg_num_mask:pg_num_mask;
 
@@ -334,14 +345,14 @@ private:
       
     case CEPH_OBJECT_LAYOUT_HASHINO:
       //ps = stable_mod(oid.bno + H(oid.bno+oid.ino)^H(oid.ino>>32), num, num_mask);
-      ps = stable_mod(oid.bno + H(oid.ino)^H(oid.ino>>32), num, num_mask);
+      ps = stable_mod(oid.bno + crush_hash32_2(oid.ino, oid.ino>>32), num, num_mask);
       break;
 
     case CEPH_OBJECT_LAYOUT_HASH:
       //ps = stable_mod(H( (oid.bno & oid.ino) ^ ((oid.bno^oid.ino) >> 32) ), num, num_mask);
       //ps = stable_mod(H(oid.bno) + H(oid.ino)^H(oid.ino>>32), num, num_mask);
       //ps = stable_mod(oid.bno + H(oid.bno+oid.ino)^H(oid.bno+oid.ino>>32), num, num_mask);
-      ps = stable_mod(oid.bno + H(oid.ino)^H(oid.ino>>32), num, num_mask);
+      ps = stable_mod(oid.bno + crush_hash32_2(oid.ino, oid.ino>>32), num, num_mask);
       break;
 
     default:
@@ -374,10 +385,9 @@ private:
        if (pg.preferred() >= 0 &&
            out_osds.count(pg.preferred()) == 0) 
          forcefeed = pg.preferred();
-       crush.do_rule(crush.rules[rule],
+       crush.do_rule(rule,
                      pg.ps(),
-                     osds, 
-                     out_osds, overload_osds,
+                     osds, pg.size(),
                      forcefeed);
       }
       break;
@@ -389,8 +399,7 @@ private:
       
     case CEPH_PG_LAYOUT_HYBRID:
       {
-       static crush::Hash H(777);
-       int h = H(pg.ps());
+       int h = crush_hash32(pg.ps());
        for (int i=0; i<pg.size(); i++) 
          osds.push_back( (h+i) % g_conf.num_osd );
       }
@@ -398,12 +407,11 @@ private:
       
     case CEPH_PG_LAYOUT_HASH:
       {
-       static crush::Hash H(777);
        for (int i=0; i<pg.size(); i++) {
          int t = 1;
          int osd = 0;
          while (t++) {
-           osd = H(i, pg.ps(), t) % g_conf.num_osd;
+           osd = crush_hash32_3(i, pg.ps(), t) % g_conf.num_osd;
            int j = 0;
            for (; j<i; j++) 
              if (osds[j] == osd) break;
index 7c68ecec2b6e45f25b887e2c9c1c461647c5f314..0e14ea3a2ed63cb65db9a255e5d58ba7443aff67 100644 (file)
@@ -31,6 +31,7 @@
 using namespace std;
 
 #include <ext/hash_map>
+#include <ext/hash_set>
 using namespace __gnu_cxx;
 
 
index 24dd9eca74234d3d8ec6a2de128251c0022b3a72..0ae9d0831b0d7d51b280c0fcf204d988ade8ec87 100644 (file)
@@ -74,8 +74,8 @@ typedef uint8_t pruleset_t;
 
 
 // crush rule ids
-#define CRUSH_REP_RULE(nrep) (100+nrep)  // replication
-#define CRUSH_RAID_RULE(num) (200+num)   // raid
+#define CRUSH_REP_RULE(nrep) (nrep)  // replication
+#define CRUSH_RAID_RULE(num) (10+num)   // raid