TiledArray  0.7.0
distributed_storage.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifndef TILEDARRAY_DISTRIBUTED_STORAGE_H__INCLUDED
21 #define TILEDARRAY_DISTRIBUTED_STORAGE_H__INCLUDED
22 
23 #include <TiledArray/pmap/pmap.h>
24 
25 namespace TiledArray {
26  namespace detail {
27 
29 
43  template <typename T>
44  class DistributedStorage : public madness::WorldObject<DistributedStorage<T> > {
45  public:
47  typedef madness::WorldObject<DistributedStorage_> WorldObject_;
48 
49  typedef std::size_t size_type;
50  typedef size_type key_type;
51  typedef T value_type;
52  typedef Future<value_type> future;
53  typedef Pmap pmap_interface;
54  typedef madness::ConcurrentHashMap<key_type, future> container_type;
55  typedef typename container_type::accessor accessor;
56  typedef typename container_type::const_accessor const_accessor;
57 
58  private:
59 
60  const size_type max_size_;
61  std::shared_ptr<pmap_interface> pmap_;
62  mutable container_type data_;
63 
64  // not allowed
66  DistributedStorage_& operator=(const DistributedStorage_&);
67 
68  future get_local(const size_type i) const {
69  TA_ASSERT(pmap_->is_local(i));
70 
71  // Return the local element.
72  const_accessor acc;
73  data_.insert(acc, i);
74  return acc->second;
75  }
76 
77  void set_handler(const size_type i, const value_type& value) {
78  future f = get_local(i);
79 
80 #ifndef NDEBUG
81  // Check that the future has not been set already.
82  if(f.probe())
83  TA_EXCEPTION("Tile has already been assigned.");
84 #endif // NDEBUG
85 
86  f.set(value);
87  }
88 
89  void get_handler(const size_type i, const typename future::remote_refT& ref) {
90  future f = get_local(i);
91  future remote_f(ref);
92  remote_f.set(f);
93  }
94 
95  void set_remote(const size_type i, const value_type& value) {
96  WorldObject_::task(owner(i), & DistributedStorage_::set_handler,
97  i, value, madness::TaskAttributes::hipri());
98  }
99 
100  struct DelayedSet : public madness::CallbackInterface {
101  private:
102  DistributedStorage_& ds_;
103  size_type index_;
104  future future_;
105 
106  public:
107 
108  DelayedSet(DistributedStorage_& ds, size_type i, const future& f) :
109  ds_(ds), index_(i), future_(f)
110  { }
111 
112  virtual ~DelayedSet() { }
113 
114  virtual void notify() {
115  ds_.set_remote(index_, future_);
116  delete this;
117  }
118  }; // struct DelayedSet
119 
120  public:
121 
123 
132  const std::shared_ptr<pmap_interface>& pmap) :
133  WorldObject_(world), max_size_(max_size),
134  pmap_(pmap),
135  data_((max_size / world.size()) + 11)
136  {
137  // Check that the process map is appropriate for this storage object
138  TA_ASSERT(pmap_);
139  TA_ASSERT(pmap_->size() == max_size);
140  TA_ASSERT(pmap_->rank() == pmap_interface::size_type(world.rank()));
141  TA_ASSERT(pmap_->procs() == pmap_interface::size_type(world.size()));
142  WorldObject_::process_pending();
143  }
144 
145  virtual ~DistributedStorage() { }
146 
147  using WorldObject_::get_world;
148 
150 
153  const std::shared_ptr<pmap_interface>& pmap() const { return pmap_; }
154 
156 
158  ProcessID owner(size_type i) const {
159  TA_ASSERT(i < max_size_);
160  TA_ASSERT(pmap_);
161  return pmap_->owner(i);
162  }
163 
165 
170  bool is_local(size_type i) const {
171  TA_ASSERT(i < max_size_);
172  TA_ASSERT(pmap_);
173  return pmap_->is_local(i);
174  }
175 
177 
181  size_type size() const { return data_.size(); }
182 
184 
189  size_type max_size() const { return max_size_; }
190 
192 
196  future get(size_type i) const {
197  TA_ASSERT(i < max_size_);
198  if(is_local(i)) {
199  return get_local(i);
200  } else {
201  // Send a request to the owner of i for the element.
202  future result;
203  WorldObject_::task(owner(i), & DistributedStorage_::get_handler, i,
204  result.remote_ref(get_world()), madness::TaskAttributes::hipri());
205 
206  return result;
207  }
208  }
209 
211 
216  void set(size_type i, const value_type& value) {
217  TA_ASSERT(i < max_size_);
218  if(is_local(i))
219  set_handler(i, value);
220  else
221  set_remote(i, value);
222  }
223 
225 
233  void set(size_type i, const future& f) {
234  TA_ASSERT(i < max_size_);
235  if(is_local(i)) {
236  const_accessor acc;
237  if(! data_.insert(acc, typename container_type::datumT(i, f))) {
238  // The element was already in the container, so set it with f.
239  future existing_f = acc->second;
240  acc.release();
241 
242  // Check that the future has not been set already.
243 #ifndef NDEBUG
244  if(existing_f.probe())
245  TA_EXCEPTION("Tile has already been assigned.");
246 #endif // NDEBUG
247  // Set the future
248  existing_f.set(f);
249  }
250  } else {
251  if(f.probe()) {
252  set_remote(i, f);
253  } else {
254  DelayedSet* set_callback = new DelayedSet(*this, i, f);
255  const_cast<future&>(f).register_callback(set_callback);
256  }
257  }
258  }
259 
260  }; // class DistributedStorage
261 
262  } // namespace detail
263 } // namespace TiledArray
264 
265 #endif // TILEDARRAY_DISTRIBUTED_STORAGE_H__INCLUDED
DistributedStorage< T > DistributedStorage_
This object type.
Distributed storage container.
madness::WorldObject< DistributedStorage_ > WorldObject_
Base object type.
const std::shared_ptr< pmap_interface > & pmap() const
Process map accessor.
Process map.
Definition: pmap.h:46
Pmap pmap_interface
Process map interface type.
ProcessID owner(size_type i) const
Element owner.
madness::ConcurrentHashMap< key_type, future > container_type
Local container type.
DistributedStorage(World &world, size_type max_size, const std::shared_ptr< pmap_interface > &pmap)
Makes an initialized, empty container with default data distribution (no communication) ...
bool is_local(size_type i) const
Local element query.
#define TA_ASSERT(a)
Definition: error.h:107
container_type::const_accessor const_accessor
Local element const accessor type.
container_type::accessor accessor
Local element accessor type.
size_type max_size() const
Max size accessor.
#define TA_EXCEPTION(m)
Definition: error.h:72
size_type size() const
Number of local elements.
std::size_t size_type
Size type.
Definition: pmap.h:48
Future< value_type > future
Element container type.