souffle  2.0.2-371-g6315b36
RecordTable.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2020, The Souffle Developers. All rights reserved.
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file RecordTable.h
12  *
13  * Data container implementing a map between records and their references.
14  * Records are separated by arity, i.e., stored in different RecordMaps.
15  *
16  ***********************************************************************/
17 
18 #pragma once
19 
20 #include "souffle/RamTypes.h"
21 #include "souffle/utility/span.h"
22 #include <cassert>
23 #include <cstddef>
24 #include <limits>
25 #include <memory>
26 #include <unordered_map>
27 #include <utility>
28 #include <vector>
29 
30 namespace souffle {
31 
32 /** @brief Bidirectional mappping between records and record references */
33 class RecordMap {
34  /** arity of record */
35  const size_t arity;
36 
37  /** hash function for unordered record map */
38  struct RecordHash {
39  std::size_t operator()(std::vector<RamDomain> record) const {
40  std::size_t seed = 0;
41  std::hash<RamDomain> domainHash;
42  for (RamDomain value : record) {
43  seed ^= domainHash(value) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
44  }
45  return seed;
46  }
47  };
48 
49  /** map from records to references */
50  // TODO (b-scholz): replace vector<RamDomain> with something more memory-frugal
51  std::unordered_map<std::vector<RamDomain>, RamDomain, RecordHash> recordToIndex;
52 
53  /** array of records; index represents record reference */
54  // TODO (b-scholz): replace vector<RamDomain> with something more memory-frugal
55  std::vector<std::vector<RamDomain>> indexToRecord;
56 
57 public:
58  explicit RecordMap(size_t arity) : arity(arity), indexToRecord(1) {} // note: index 0 element left free
59 
60  /** @brief converts record to a record reference */
61  // TODO (b-scholz): replace vector<RamDomain> with something more memory-frugal
62  RamDomain pack(std::vector<RamDomain> vector) {
63  RamDomain index;
64 #pragma omp critical(record_pack)
65  {
66  auto pos = recordToIndex.find(vector);
67  if (pos != recordToIndex.end()) {
68  index = pos->second;
69  } else {
70 #pragma omp critical(record_unpack)
71  {
72  assert(indexToRecord.size() <= std::numeric_limits<RamUnsigned>::max());
73  index = ramBitCast(RamUnsigned(indexToRecord.size()));
74  recordToIndex[vector] = index;
75  indexToRecord.push_back(std::move(vector));
76  }
77  }
78  }
79  return index;
80  }
81 
82  /** @brief convert record pointer to a record reference */
83  RamDomain pack(const RamDomain* tuple) {
84  // TODO (b-scholz): data is unnecessarily copied
85  // for a successful lookup. To avoid this, we should
86  // compute a hash of the pointer-array and traverse through
87  // the bucket list of the unordered map finding the record.
88  // Note that in case of non-existence, the record still needs to be
89  // copied for the newly created entry but this will be the less
90  // frequent case.
91  std::vector<RamDomain> tmp(arity);
92  for (size_t i = 0; i < arity; i++) {
93  tmp[i] = tuple[i];
94  }
95  return pack(std::move(tmp));
96  }
97 
98  /** @brief convert record reference to a record pointer */
99  const RamDomain* unpack(RamDomain index) const {
100  const RamDomain* res;
101 #pragma omp critical(record_unpack)
102  res = indexToRecord[index].data();
103  return res;
104  }
105 };
106 
107 class RecordTable {
108 public:
109  RecordTable() = default;
110  virtual ~RecordTable() = default;
111 
112  /** @brief convert record to record reference */
113  RamDomain pack(const RamDomain* tuple, size_t arity) {
114  return lookupArity(arity).pack(tuple);
115  }
116  /** @brief convert record reference to a record */
117  const RamDomain* unpack(RamDomain ref, size_t arity) const {
118  std::unordered_map<size_t, RecordMap>::const_iterator iter;
119 #pragma omp critical(RecordTableGetForArity)
120  {
121  // Find a previously emplaced map
122  iter = maps.find(arity);
123  }
124  assert(iter != maps.end() && "Attempting to unpack record for non-existing arity");
125  return (iter->second).unpack(ref);
126  }
127 
128 private:
129  /** @brief lookup RecordMap for a given arity; if it does not exist, create new RecordMap */
130  RecordMap& lookupArity(size_t arity) {
131  std::unordered_map<size_t, RecordMap>::iterator mapsIterator;
132 #pragma omp critical(RecordTableGetForArity)
133  {
134  // This will create a new map if it doesn't exist yet.
135  mapsIterator = maps.emplace(arity, arity).first;
136  }
137  return mapsIterator->second;
138  }
139 
140  /** Arity/RecordMap association */
141  std::unordered_map<size_t, RecordMap> maps;
142 };
143 
144 /** @brief helper to convert tuple to record reference for the synthesiser */
145 template <std::size_t Arity>
146 RamDomain pack(RecordTable& recordTab, Tuple<RamDomain, Arity> const& tuple) {
147  return recordTab.pack(tuple.data(), Arity);
148 }
149 
150 /** @brief helper to convert tuple to record reference for the synthesiser */
151 template <std::size_t Arity>
153  return recordTab.pack(tuple.data(), Arity);
154 }
155 
156 } // namespace souffle
souffle::RamUnsigned
uint32_t RamUnsigned
Definition: RamTypes.h:58
souffle::RecordMap::RecordHash
hash function for unordered record map
Definition: RecordTable.h:52
souffle::RamDomain
int32_t RamDomain
Definition: RamTypes.h:56
souffle::span
tcb::span< A, E > span
Definition: span.h:659
souffle::RecordTable
Definition: RecordTable.h:114
souffle::RecordMap::unpack
const RamDomain * unpack(RamDomain index) const
convert record reference to a record pointer
Definition: RecordTable.h:113
souffle::RecordTable::~RecordTable
virtual ~RecordTable()=default
souffle::RecordTable::unpack
const RamDomain * unpack(RamDomain ref, size_t arity) const
convert record reference to a record
Definition: RecordTable.h:124
i
size_t i
Definition: json11.h:663
souffle::RecordMap::pack
RamDomain pack(std::vector< RamDomain > vector)
converts record to a record reference
Definition: RecordTable.h:76
span.h
souffle::tuple::data
const RamDomain * data
Allows printing using WriteStream.
Definition: SouffleInterface.h:498
souffle::RecordMap
Bidirectional mappping between records and record references.
Definition: RecordTable.h:40
souffle::pack
RamDomain pack(RecordTable &recordTab, Tuple< RamDomain, Arity > const &tuple)
helper to convert tuple to record reference for the synthesiser
Definition: RecordTable.h:153
souffle::RecordTable::pack
RamDomain pack(const RamDomain *tuple, size_t arity)
convert record to record reference
Definition: RecordTable.h:120
souffle::RecordTable::RecordTable
RecordTable()=default
souffle::RecordTable::maps
std::unordered_map< size_t, RecordMap > maps
Arity/RecordMap association.
Definition: RecordTable.h:148
souffle::RecordMap::indexToRecord
std::vector< std::vector< RamDomain > > indexToRecord
array of records; index represents record reference
Definition: RecordTable.h:69
souffle::RecordMap::RecordMap
RecordMap(size_t arity)
Definition: RecordTable.h:72
RamTypes.h
souffle::RecordMap::recordToIndex
std::unordered_map< std::vector< RamDomain >, RamDomain, RecordHash > recordToIndex
map from records to references
Definition: RecordTable.h:65
souffle::RecordMap::RecordHash::operator()
std::size_t operator()(std::vector< RamDomain > record) const
Definition: RecordTable.h:53
souffle::RecordMap::arity
const size_t arity
arity of record
Definition: RecordTable.h:49
souffle
Definition: AggregateOp.h:25
souffle::RecordTable::lookupArity
RecordMap & lookupArity(size_t arity)
lookup RecordMap for a given arity; if it does not exist, create new RecordMap
Definition: RecordTable.h:137
souffle::ramBitCast
To ramBitCast(From source)
In C++20 there will be a new way to cast between types by reinterpreting bits (std::bit_cast),...
Definition: RamTypes.h:87
souffle::tuple
Defines a tuple for the OO interface such that relations with varying columns can be accessed.
Definition: SouffleInterface.h:443