NVMTable.hpp 17.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * Copyright (c) 2014-17 The PipeFabric team,
 *                       All Rights Reserved.
 *
 * This file is part of the PipeFabric package.
 *
 * PipeFabric is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License (GPL) as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This package is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file LICENSE.
 * If not you can find the GPL at http://www.gnu.org/copyleft/gpl.html
 */

#ifndef NVMTable_hpp_
#define NVMTable_hpp_

#include <iostream>
#include <vector>
#include <unordered_map>
#include <functional>
#include <exception>
#include <iterator>
#include <stdint.h>
#include <unistd.h>
33
#include <cstdio>
34
#include <type_traits>
35

36
#include <boost/signals2.hpp>
37

38
39
40
41
42
43
44
45
#include <libpmemobj++/make_persistent.hpp>
#include <libpmemobj++/p.hpp>
#include <libpmemobj++/persistent_ptr.hpp>
#include <libpmemobj++/pool.hpp>
#include <libpmemobj++/transaction.hpp>
#include <libpmemobj++/utils.hpp>
#include <libpmempool.h>

46
#include "fmt/format.h"
47
#include "PTable.hpp"
48

49
#include "core/Tuple.hpp"
50
51
#include "table/TableException.hpp"
#include "table/BaseTable.hpp"
Philipp Götze's avatar
Backup    
Philipp Götze committed
52
#include "table/TableInfo.hpp"
53

Philipp Götze's avatar
Backup    
Philipp Götze committed
54
namespace pfabric {
55

56
57
58
//TODO: Maybe the pmem device path prefix should be a CMake variable?
const std::string pathPrefix = "/mnt/pmem/test/";

Philipp Götze's avatar
Philipp Götze committed
59
namespace detail {
60

Philipp Götze's avatar
Philipp Götze committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
struct GetType {
  template<typename T>
  static auto apply(T &t) {
    return ColumnInfo::Void_Type;
  }
};

template<>
inline auto GetType::apply<int>(int &t) {
  return ColumnInfo::Int_Type;
}

template<>
inline auto GetType::apply<double>(double &t) {
  return ColumnInfo::Double_Type;
}

template<>
inline auto GetType::apply<std::string>(std::string &t) {
  return ColumnInfo::String_Type;
}

template<class Tuple, std::size_t CurrentIndex>
struct TupleTypes;

template<class Tuple, std::size_t CurrentIndex>
struct TupleTypes {
  static void apply(Tuple tp, std::vector<ColumnInfo> &cols) {
    TupleTypes<Tuple, CurrentIndex - 1>::apply(tp, cols);
    auto type = GetType::apply(std::get<CurrentIndex - 1>(tp));
    cols.push_back(ColumnInfo("", type));
  }
};
94

Philipp Götze's avatar
Philipp Götze committed
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
template<class Tuple>
struct TupleTypes<Tuple, 1> {
  static void apply(Tuple tp, std::vector<ColumnInfo> &cols) {
    auto type = GetType::apply(std::get<0>(tp));
    cols.push_back(ColumnInfo("", type));
  }
};

template<class Tuple>
TableInfo constructSchema(const std::string &tableName) {
  typedef typename Tuple::Base Base;
  Base t; // create default initialized std::tuple

  std::vector<ColumnInfo> cols;
  detail::TupleTypes<Base, std::tuple_size<Base>::value>::apply(t, cols);
  TableInfo tInfo(tableName);
  tInfo.setColumns(cols);
  return tInfo;
}
114
115
116
117
118
119
120
121

template<typename T>
struct is_tuple_impl : std::false_type {};
template<typename... Ts>
struct is_tuple_impl<pfabric::Tuple<Ts...>> : std::true_type {};
template<typename T>
struct is_tuple : is_tuple_impl<std::decay_t<T>> {};

Philipp Götze's avatar
Philipp Götze committed
122
123
124
125
126
127
128
129
} /* namespace detail */

using nvml::obj::delete_persistent;
using nvml::obj::make_persistent;
using nvml::obj::p;
using nvml::obj::persistent_ptr;
using nvml::obj::pool;
using nvml::obj::transaction;
130
131
using ptable::PTable;
using ptable::PTuple;
Philipp Götze's avatar
Philipp Götze committed
132
133
134
135

template<typename RecordType, typename KeyType>
class NVMIterator {
 public:
136
137
  static_assert(detail::is_tuple<RecordType>::value, "Value type must be a pfabric::Tuple");
  using TupleType = typename RecordType::Base;
138
139
//  using Predicate = std::function<bool(const PTuple<TupleType, KeyType> &)>;
  using Predicate = std::function<bool(const RecordType &)>;
140
  using PTableType = PTable<TupleType, KeyType>;
Philipp Götze's avatar
Philipp Götze committed
141
142
143

  explicit NVMIterator() {
  }
144

Philipp Götze's avatar
Philipp Götze committed
145
146
  explicit NVMIterator(typename PTableType::iterator &&_iter, typename PTableType::iterator &&_end, Predicate _pred) :
    iter(std::move(_iter)), end(std::move(_end)), pred(_pred) {
147

148
    while (isValid() && !pred(*(*iter).createTuple()))
Philipp Götze's avatar
Philipp Götze committed
149
150
      iter++;
  }
151

Philipp Götze's avatar
Philipp Götze committed
152
153
  NVMIterator &operator++() {
    iter++;
154
    while (isValid() && !pred(*(*iter).createTuple()))
155
      iter++;
Philipp Götze's avatar
Philipp Götze committed
156
157
    return *this;
  }
158

Philipp Götze's avatar
Philipp Götze committed
159
160
161
162
163
  NVMIterator operator++(int) {
    auto tmp = *this;
    ++(*this);
    return tmp;
  }
164

Philipp Götze's avatar
Philipp Götze committed
165
166
167
  bool isValid() const {
    return iter != end;
  }
168

Philipp Götze's avatar
Philipp Götze committed
169
  SmartPtr<RecordType> operator*() {
170
171
    SmartPtr<RecordType> tptr(new RecordType(*(*iter).createTuple()));
    return tptr; //TODO: Is this to expensive?
Philipp Götze's avatar
Philipp Götze committed
172
  }
173

Philipp Götze's avatar
Philipp Götze committed
174
175
176
177
178
 protected:
  // PTable Iterator
  typename PTableType::iterator iter, end;
  // Selection predicate
  Predicate pred;
179

Philipp Götze's avatar
Philipp Götze committed
180
};
181

Philipp Götze's avatar
Philipp Götze committed
182
183
template<typename RecordType, typename KeyType>
inline NVMIterator<RecordType, KeyType> makeNVMIterator(
184
185
  typename PTable<typename RecordType::Base, KeyType>::iterator &&iter,
  typename PTable<typename RecordType::Base, KeyType>::iterator &&end,
Philipp Götze's avatar
Philipp Götze committed
186
187
188
  typename NVMIterator<RecordType, KeyType>::Predicate pred) {
  return NVMIterator<RecordType, KeyType>(std::move(iter), std::move(end), pred);
}
189

Philipp Götze's avatar
Philipp Götze committed
190
191
/**************************************************************************//**
 * \brief NVMTable is a class for storing a relation of tuples of the same type.
192
193
 *
 * Table implements a relational table for storing tuples of a given type
Philipp Götze's avatar
Philipp Götze committed
194
 * \c RecordType which are indexed by the key of type \c KeyType.
195
196
197
 * Table supports inserting, updating, deleting of tuples as well as scans
 * within a transactional context (not yet implemented).
 *
Philipp Götze's avatar
Philipp Götze committed
198
 * \tparam RecordType
199
 *         the data type of the tuples (typically a TuplePtr or Tuple)
Philipp Götze's avatar
Philipp Götze committed
200
 * \tparam KeyType
201
 *         the data type of the key column (default = int)
Philipp Götze's avatar
Philipp Götze committed
202
203
204
205
 *****************************************************************************/
template<typename RecordType, typename KeyType = DefaultKeyType>
class NVMTable : public BaseTable {
 public:
206
207
208
  static_assert(detail::is_tuple<RecordType>::value, "Value type must be a pfabric::Tuple");
  using TupleType = typename RecordType::Base;
  using PTableType = PTable<TupleType, KeyType>;
209

Philipp Götze's avatar
Philipp Götze committed
210
211
212
  struct root {
    persistent_ptr<PTableType> pTable;
  };
213

214
215
  /** typedef for a updater function which returns a modification of the parameter tuple */
  using UpdaterFunc = std::function<void(RecordType &)>;
216

217
218
219
220
221
  /** typedefs for a function performing updates + deletes. Similar to UpdaterFunc
   *  it allows to update the tuple, but also to delete it (indictated by the
   *  setting the bool component of \c UpdateResult to false)
   **/
  using UpdelFunc = std::function<bool(RecordType &)>;
222

223
224
  /** typedef for a callback function which is invoked when the table was updated */
  using ObserverCallback = boost::signals2::signal<void(const RecordType &, TableParams::ModificationMode)>;
225

226
227
  /** typedef for an iterator to scan the table */
  using TableIterator = NVMIterator<RecordType, KeyType>;
228

229
230
  /** typedef for a predicate evaluated using a scan: see \TableIterator for details */
  using Predicate = typename TableIterator::Predicate;
231

Philipp Götze's avatar
Philipp Götze committed
232
233
234
235
236
237
  /************************************************************************//**
   * \brief Constructor for creating an empty table with only a given name.
   *****************************************************************************/
  NVMTable(const std::string &tableName) : BaseTable(detail::constructSchema<RecordType>(tableName)) {
    openOrCreateTable(detail::constructSchema<RecordType>(tableName));
  }
238

Philipp Götze's avatar
Philipp Götze committed
239
240
241
242
243
244
245
  /************************************************************************//**
   * \brief Constructor for creating an empty table with a given schema.
   *****************************************************************************/
  NVMTable(const TableInfo &tInfo) :
    BaseTable(tInfo) {
    openOrCreateTable(tInfo);
  }
246

Philipp Götze's avatar
Philipp Götze committed
247
248
249
250
251
252
  /************************************************************************//**
   * \brief Destructor for table.
   *****************************************************************************/
  ~NVMTable() {
    // pop.close();
  }
253

Philipp Götze's avatar
Philipp Götze committed
254
255
256
257
258
259
260
261
262
  /************************************************************************//**
   * \brief Insert a tuple.
   *
   * Insert the given tuple \rec with the given key into the table. After the insert
   * all observers are notified.
   *
   * \param key the key value of the tuple
   * \param rec the actual tuple
   *****************************************************************************/
263
  void insert(KeyType key, const RecordType &rec) noexcept(false) {
264
265
    pTable->insert(key, rec.data());
    notifyObservers(rec, TableParams::Insert, TableParams::Immediate);
Philipp Götze's avatar
Philipp Götze committed
266
  }
267

Philipp Götze's avatar
Philipp Götze committed
268
269
270
271
272
273
274
275
276
277
  /************************************************************************//**
   * \brief Delete a tuple.
   *
   * Delete the tuples associated with the given key from the table
   * and inform the observers.
   *
   * \param key the key for which the tuples are deleted from the table
   * \return the number of deleted tuples
   *****************************************************************************/
  unsigned long deleteByKey(KeyType key) {
278
    return pTable->deleteByKey(key);
Philipp Götze's avatar
Philipp Götze committed
279
  }
280

Philipp Götze's avatar
Philipp Götze committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
  /************************************************************************//**
   * \brief Delete all tuples satisfying a predicate.
   *
   * Delete all tuples from the table which satisfy the given predicate.
   *
   * \param func a predicate function returning true if the given tuple should be
   *             deleted
   * \return the number of deleted tuples
   *****************************************************************************/
  unsigned long deleteWhere(Predicate func) {
    unsigned long num = 0;
    //TODO:
    return num;
  }
295

Philipp Götze's avatar
Philipp Götze committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
  /************************************************************************//**
   * \brief Update or delete the tuple specified by the given key.
   *
   * Update or delete the tuple in the table associated with the given key.
   * The actual modification is done by the updater function specified as parameter.
   *
   * \param key the key of the tuple to be modified
   * \param func a function performing the modification by returning a modified
   *        tuple + a bool value indicating whether the tuple shall be kept (=true)
   *        or deleted (=false)
   * \return the number of modified tuples
   *****************************************************************************/
  unsigned long updateOrDeleteByKey(KeyType key, UpdelFunc ufunc) {
    //TODO:
    return 0;
  }
312

Philipp Götze's avatar
Philipp Götze committed
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
  /************************************************************************//**
   * \brief Update the tuple specified by the given key.
   *
   * Update the tuple in the table associated with the given key.
   * The actual modification is done by the updater function specified as parameter.
   *
   * \param key the key of the tuple to be modified
   * \param func a function performing the modification by returning a modified
   *        tuple
   * \return the number of modified tuples
   *****************************************************************************/
  unsigned long updateByKey(KeyType key, UpdaterFunc ufunc) {
    //TODO:
    return 0;
  }
328

Philipp Götze's avatar
Philipp Götze committed
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
  /************************************************************************//**
   * \brief Update all tuples satisfying the given predicate.
   *
   * Update all tuples in the table which satisfy the given predicate.
   * The actual modification is done by the updater function specified as parameter.
   *
   * \param pfunc a predicate func returning true for a tuple to be modified
   * \param func a function performing the modification by returning a modified
   *        tuple
   * \return the number of modified tuples
   ***************************************************************************/
  unsigned long updateWhere(Predicate pfunc, UpdaterFunc ufunc) {
    unsigned long num = 0;
    //TODO:
    return num;
  }
345

Philipp Götze's avatar
Philipp Götze committed
346
347
348
349
350
351
352
353
354
  /************************************************************************//**
   * \brief Return the tuple associated with the given key.
   *
   * Return the tuple from the table that is associated with the given
   * key. If the key doesn't exist, an exception is thrown.
   *
   * \param key the key value
   * \return the tuple associated with the given key
   *****************************************************************************/
355
356
  const SmartPtr<RecordType> getByKey(KeyType key) noexcept(false) {
    //TODO: ugly, can we do better?
357
358
359
360
361
362
    try {
      SmartPtr<RecordType> tptr(new RecordType(*pTable->getByKey(key).createTuple()));
      return tptr;
    } catch (ptable::PTableException &pex) {
      throw TableException(pex.what());
    }
Philipp Götze's avatar
Philipp Götze committed
363
  }
364

Philipp Götze's avatar
Philipp Götze committed
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
  /************************************************************************//**
   * \brief Return a pair of iterators for scanning the table with a
   *        selection predicate.
   *
   * Return an iterator that allows to scan the whole table
   * and visiting only tuples which satisfy the given predicate
   * as in the following example:
   * \code
   * auto iter = testTable->select([](const MyTuple& tp) {
   *                 return get<0>(tp) % 2 == 0;
   *               });
   * for (; iter.isValid(); i++)
   *    // do something with *i
   * \endcode
   *
   * \param func a function pointer to a predicate
   * \return a pair of iterators
   *****************************************************************************/
  TableIterator select(Predicate func) {
    return makeNVMIterator<RecordType, KeyType>(std::move(pTable->begin()), std::move(pTable->end()), func);
  }
386

Philipp Götze's avatar
Philipp Götze committed
387
388
389
390
391
392
393
394
395
396
397
398
399
400
  /************************************************************************//**
   * \brief Return a pair of iterators for scanning the whole table.
   *
   * Return an iterator that allows to scan the whole table
   * as in the following example:
   * \code
   * auto iter = testTable->select();
   * for (; iter.isValid(); i++)
   *    // do something with *i
   * \endcode
   *
   * \return a pair of iterators
   *****************************************************************************/
  TableIterator select() {
401
402
    auto alwaysTrue = [](const RecordType &) { return true; };
//    auto alwaysTrue = [](const PTuple<TupleType, KeyType> &) { return true; };
Philipp Götze's avatar
Philipp Götze committed
403
    return makeNVMIterator<RecordType, KeyType>(std::move(pTable->begin()), std::move(pTable->end()), alwaysTrue);
404

Philipp Götze's avatar
Philipp Götze committed
405
  }
406

Philipp Götze's avatar
Philipp Götze committed
407
408
409
410
411
412
413
414
  /************************************************************************//**
   * \brief Return the number of tuples stored in the table.
   *
   * \return the number of tuples
   *****************************************************************************/
  unsigned long size() const {
    return pTable->count();
  }
415

Philipp Götze's avatar
Philipp Götze committed
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
  /************************************************************************//**
   * \brief Register an observer
   *
   * Registers an observer (a slot) which is notified in case of updates on the table.
   *
   * \param cb the observer (slot)
   * \param mode the nofication mode (immediate or defered)
   *****************************************************************************/
  void registerObserver(typename ObserverCallback::slot_type const &cb,
                        TableParams::NotificationMode mode) {
    switch (mode) {
      case TableParams::Immediate:mImmediateObservers.connect(cb);
        break;
      case TableParams::OnCommit:mDeferredObservers.connect(cb);
        break;
431
    }
Philipp Götze's avatar
Philipp Götze committed
432
  }
433

Philipp Götze's avatar
Philipp Götze committed
434
  void drop() {
435
    auto pop = pool_by_pptr(q);
Philipp Götze's avatar
Philipp Götze committed
436
437
438
439
440
441
442
    transaction::exec_tx(pop, [&] {
      delete_persistent<PTableType>(pTable);
      pTable = nullptr;
      delete_persistent<root>(q);
      q = nullptr;
    });
    pop.close();
443
    pmempool_rm((pathPrefix + BaseTable::mTableInfo->tableName() + ".db").c_str(), 1);
Philipp Götze's avatar
Philipp Götze committed
444
445
    //std::remove((BaseTable::mTableInfo->tableName()+".db").c_str());
  }
446

Philipp Götze's avatar
Philipp Götze committed
447
448
449
450
451
  void print() {
    pTable->print(false);
  }

 private:
452
  void openOrCreateTable(const TableInfo &tableInfo) noexcept(false) {
453
454
455
    std::string path = pathPrefix + tableInfo.tableName() + ".db";
    pool<root> pop;

Philipp Götze's avatar
Philipp Götze committed
456
    if (access(path.c_str(), F_OK) != 0) {
457
      pop = pool<root>::create(path, ptable::LAYOUT, 64 * 1024 * 1024);    //, (size_t)blockSize, 0666);
Philipp Götze's avatar
Philipp Götze committed
458
      transaction::exec_tx(pop, [&] {
459
460
461
462
463
464
465
466
467
468
469
470
471
472
        ptable::ColumnVector cVector;
        for (auto &c : tableInfo) {
          switch (c.getType()) {
            case ColumnInfo::Void_Type:cVector.push_back(ptable::Column(c.getName(), ptable::Void_Type));
              break;
            case ColumnInfo::Int_Type:cVector.push_back(ptable::Column(c.getName(), ptable::Int_Type));
              break;
            case ColumnInfo::Double_Type:cVector.push_back(ptable::Column(c.getName(), ptable::Double_Type));
              break;
            case ColumnInfo::String_Type:cVector.push_back(ptable::Column(c.getName(), ptable::String_Type));
          };
        }
        ptable::VTableInfo vTableInfo(tableInfo.tableName(), cVector);
        auto tbl = make_persistent<PTableType>(vTableInfo);
Philipp Götze's avatar
Philipp Götze committed
473
474
475
        pop.get_root()->pTable = tbl;
      });
    } else {
476
      pop = pool<root>::open(path, ptable::LAYOUT);
477
    }
Philipp Götze's avatar
Philipp Götze committed
478
479
480
    q = pop.get_root();
    pTable = q->pTable;
  }
481

Philipp Götze's avatar
Philipp Götze committed
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  /************************************************************************//**
   * \brief Perform the actual notification
   *
   * Notify all registered observers about a update.
   *
   * \param rec the modified tuple
   * \param mode the modification mode (insert, update, delete)
   * \param notify the nofication mode (immediate or defered)
   *****************************************************************************/
  void notifyObservers(const RecordType &rec, TableParams::ModificationMode mode,
                       TableParams::NotificationMode notify) {
    if (notify == TableParams::Immediate) {
      mImmediateObservers(rec, mode);
    } else {
      // TODO: implement defered notification
      mDeferredObservers(rec, mode);
498
    }
Philipp Götze's avatar
Philipp Götze committed
499
  }
500

Philipp Götze's avatar
Philipp Götze committed
501
502
503
  persistent_ptr<struct root> q;
  persistent_ptr<PTableType> pTable;
  ObserverCallback mImmediateObservers, mDeferredObservers;
504

Philipp Götze's avatar
Philipp Götze committed
505
}; /* class NVMTable */
Philipp Götze's avatar
Backup    
Philipp Götze committed
506
507
508
509

} /* namespace pfabric */

#endif /* NVMTable_hpp_ */