OpenCog Framework  Branch: master, revision 6f0b7fc776b08468cf1b74aa9db028f387b4f0c0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
AtomSpace.cc
Go to the documentation of this file.
1 /*
2  * opencog/atomspace/AtomSpace.cc
3  *
4  * Copyright (c) 2008-2010 OpenCog Foundation
5  * Copyright (c) 2009, 2013 Linas Vepstas
6  * All Rights Reserved
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU Affero General Public License v3 as
10  * published by the Free Software Foundation and including the exceptions
11  * at http://opencog.org/wiki/Licenses
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU Affero General Public License
19  * along with this program; if not, write to:
20  * Free Software Foundation, Inc.,
21  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22  */
23 
24 #include <string>
25 #include <iostream>
26 #include <fstream>
27 #include <list>
28 
29 #include <stdlib.h>
30 
31 #include <boost/bind.hpp>
32 
34 #include <opencog/atomspace/Link.h>
35 #include <opencog/atomspace/Node.h>
36 // #include <opencog/atoms/bind/DeleteLink.h>
38 #include <opencog/util/Logger.h>
39 #include <opencog/util/oc_assert.h>
40 
41 #include "AtomSpace.h"
42 
43 //#define DPRINTF printf
44 #define DPRINTF(...)
45 
46 using std::string;
47 using std::cerr;
48 using std::cout;
49 using std::endl;
50 using std::min;
51 using std::max;
52 using namespace opencog;
53 
54 // ====================================================================
55 
57  atomTable(parent? &parent->atomTable : NULL, this),
58  bank(atomTable),
59  backing_store(NULL)
60 {
61 }
62 
64 {
65  // Be sure to disconnect the attention bank signals before the
66  // atom table destructor runs. XXX FIXME yes this is an ugly hack.
67  bank.shutdown();
68 }
69 
71  atomTable(NULL),
72  bank(atomTable),
73  backing_store(NULL)
74 {
75  throw opencog::RuntimeException(TRACE_INFO,
76  "AtomSpace - Cannot copy an object of this class");
77 }
78 
80 {
81  throw opencog::RuntimeException(TRACE_INFO,
82  "AtomSpace - Cannot copy an object of this class");
83 }
84 
85 
86 // ====================================================================
87 
89 {
90  backing_store = bs;
91 }
92 
94 {
95  if (bs == backing_store) backing_store = NULL;
96 }
97 
98 // ====================================================================
99 
101 {
102  // Is this atom already in the atom table?
103  Handle hexist(atomTable.getHandle(atom));
104  if (hexist) return hexist;
105 
106  // If we are here, the AtomTable does not yet know about this atom.
107  // Maybe the backing store knows about this atom.
108  Type t = atom->getType();
109  if (backing_store and not backing_store->ignoreType(t)) {
110 
111  Handle ha(atom);
112  AtomPtr ba(backing_store->getAtom(ha));
113  if (ba) {
114  return atomTable.add(ba, async);
115  }
116  }
117 
118  // If we are here, neither the AtomTable nor backing store know
119  // about this atom. Just add it. If it is a DeleteLink, then the
120  // addition will fail. Deal with it.
121  Handle rh;
122  try {
123  rh = atomTable.add(atom, async);
124  }
125  catch (const DeleteException& ex) {
126  // Atom deletion has not been implemented in the backing store
127  // This is a major to-do item.
128  if (backing_store)
129 // Under construction ....
130  throw RuntimeException(TRACE_INFO, "Not implemented!!!");
131  }
132  return rh;
133 }
134 
135 Handle AtomSpace::add_node(Type t, const string& name,
136  bool async)
137 {
138  // Is this atom already in the atom table?
139  Handle hexist(atomTable.getHandle(t, name));
140  if (hexist) return hexist;
141 
142  // If we are here, the AtomTable does not yet know about this atom.
143  // Maybe the backing store knows about this atom.
144  if (backing_store and not backing_store->ignoreType(t))
145  {
146  NodePtr n(backing_store->getNode(t, name.c_str()));
147  if (n) return atomTable.add(n, async);
148  }
149 
150  // If we are here, neither the AtomTable nor backing store know about
151  // this atom. Just add it.
152  return atomTable.add(createNode(t, name), async);
153 }
154 
155 Handle AtomSpace::get_node(Type t, const string& name)
156 {
157  // Is this atom already in the atom table?
158  Handle hexist = atomTable.getHandle(t, name);
159  if (hexist) return hexist;
160 
161  // If we are here, the AtomTable does not yet know about this atom.
162  // Maybe the backing store knows about this atom.
163  if (backing_store and not backing_store->ignoreType(t))
164  {
165  NodePtr n(backing_store->getNode(t, name.c_str()));
166  if (n) {
167  return atomTable.add(n, false);
168  }
169  }
170 
171  // If we are here, nobody knows about this.
172  return Handle::UNDEFINED;
173 }
174 
176  bool async)
177 {
178  // Is this atom already in the atom table?
179  Handle hexist = atomTable.getHandle(t, outgoing);
180  if (hexist) return hexist;
181 
182  // If we are here, the AtomTable does not yet know about this atom.
183  // Maybe the backing store knows about this atom.
184  if (backing_store and not backing_store->ignoreType(t))
185  {
186  // If any of the outgoing set is ignorable, we will not
187  // fetch the thing from the backing store.
188  if (not std::any_of(outgoing.begin(), outgoing.end(),
189  [this](Handle ho) { return backing_store->ignoreAtom(ho); }))
190  {
191  LinkPtr l(backing_store->getLink(t, outgoing));
192  if (l) {
193  // Put the atom into the atomtable, so it gets placed
194  // in indices, so we can find it quickly next time.
195  return atomTable.add(l, async);
196  }
197  }
198  }
199 
200  // If we are here, neither the AtomTable nor backing store know
201  // about this atom. Just add it. If it is a DeleteLink, then the
202  // addition will fail. Deal with it.
203  Handle rh;
204  try {
205  rh = atomTable.add(createLink(t, outgoing), async);
206  }
207  catch (const DeleteException& ex) {
208  // Atom deletion has not been implemented in the backing store
209  // This is a major to-do item.
210  if (backing_store)
211 // Under construction ....
212  throw RuntimeException(TRACE_INFO, "Not implemented!!!");
213  }
214  return rh;
215 }
216 
218 {
219  // Is this atom already in the atom table?
220  Handle hexist = atomTable.getHandle(t, outgoing);
221  if (hexist) return hexist;
222 
223  // If we are here, the AtomTable does not yet know about this atom.
224  // Maybe the backing store knows about this atom.
225  if (backing_store and not backing_store->ignoreType(t))
226  {
227  // If any of the outgoing set is ignorable, we will not
228  // fetch the thing from the backing store.
229  if (not std::any_of(outgoing.begin(), outgoing.end(),
230  [this](Handle ho) { return backing_store->ignoreAtom(ho); }))
231  {
232  LinkPtr l(backing_store->getLink(t, outgoing));
233  if (l) {
234  // Register the atom with the atomtable (so it gets placed in
235  // indices)
236  return atomTable.add(l, false);
237  }
238  }
239  }
240 
241  // If we are here, nobody knows about this.
242  return Handle::UNDEFINED;
243 }
244 
246 {
247  if (NULL == backing_store)
248  throw RuntimeException(TRACE_INFO, "No backing store");
249 
251 }
252 
254 {
255  if (NULL == backing_store)
256  throw RuntimeException(TRACE_INFO, "No backing store");
257 
258  // OK, we have to handle three distinct cases.
259  // 1) If atom table already knows about this uuid or atom, then
260  // this function returns the atom-table's version of the atom.
261  // In particular, no attempt is made to reconcile the possibly
262  // differing truth values in the atomtable vs. backing store.
263  // 2) If the handle h holds a UUID but no atom pointer, then get
264  // the corresponding atom from storage, and add it to the atom
265  // table.
266  // 3) If the handle h contains a pointer to an atom (that is not
267  // in the atom table), then assume that atom is from some previous
268  // (recursive) query, and add it to the atomtable.
269  // For both case 2 & 3, if the atom is a link, then it's outgoing
270  // set is fetched as well, as currently, a link cannot be added to
271  // the atomtable, unless all of its outgoing set already is in the
272  // atomtable.
273 
274  // Case 1:
275  Handle hb(atomTable.getHandle(h));
276  if (atomTable.holds(hb))
277  return hb;
278 
279  // Case 2 & 3:
280  // If we don't have the atom for this UUID, then go get it.
281  if (NULL == h.operator->()) {
283 
284  // If we still don't have an atom, then the requested UUID
285  // was "insane", that is, unknown by either the atom table
286  // (case 1) or the backend.
287  if (NULL == a.operator->())
288  throw RuntimeException(TRACE_INFO,
289  "Asked backend for an unknown handle; UUID=%lu\n",
290  h.value());
291  h = a;
292  }
293 
294  // For links, must perform a recursive fetch, as otherwise
295  // the atomTable.add() below will throw an error.
296  LinkPtr l(LinkCast(h));
297  if (l) {
298  const HandleSeq& ogs = l->getOutgoingSet();
299  size_t arity = ogs.size();
300  for (size_t i=0; i<arity; i++)
301  {
302  Handle oh(fetch_atom(ogs[i]));
303  if (oh != ogs[i]) throw RuntimeException(TRACE_INFO,
304  "Unexpected handle mismatch! Expected %lu got %lu\n",
305  ogs[i].value(), oh.value());
306  }
307  }
308 
309  return atomTable.add(h, false);
310 }
311 
313 {
314  Handle he(atomTable.getHandle(h));
315  if (he) return he;
316  if (backing_store)
317  return fetch_atom(h);
318  return Handle::UNDEFINED;
319 }
320 
322 {
323  if (NULL == backing_store)
324  throw RuntimeException(TRACE_INFO, "No backing store");
325 
326  h = get_atom(h);
327 
328  if (Handle::UNDEFINED == h) return Handle::UNDEFINED;
329 
330  // Get everything from the backing store.
332  size_t isz = iset.size();
333  for (size_t i=0; i<isz; i++) {
334  Handle hi(iset[i]);
335  if (recursive) {
336  fetch_incoming_set(hi, true);
337  } else {
338  get_atom(hi);
339  }
340  }
341  return h;
342 }
343 
344 bool AtomSpace::remove_atom(Handle h, bool recursive)
345 {
346  if (backing_store) {
347  // Atom deletion has not been implemented in the backing store
348  // This is a major to-do item.
349 // Under construction ....
350  throw RuntimeException(TRACE_INFO, "Not implemented!!!");
351  }
352  return 0 < atomTable.extract(h, recursive).size();
353 }
354 
356 {
357  std::vector<Handle> allAtoms;
358 
359  atomTable.getHandlesByType(back_inserter(allAtoms), ATOM, true, false);
360 
361  DPRINTF("atoms in allAtoms: %lu\n", allAtoms.size());
362 
363  Logger::Level save = logger().getLevel();
364  logger().setLevel(Logger::DEBUG);
365 
366  // XXX FIXME TODO This is a stunningly inefficient way to clear the
367  // atomspace! This will take minutes on any decent-sized atomspace!
368  std::vector<Handle>::iterator i;
369  for (i = allAtoms.begin(); i != allAtoms.end(); ++i) {
370  purge_atom(*i, true);
371  }
372 
373  allAtoms.clear();
374  atomTable.getHandlesByType(back_inserter(allAtoms), ATOM, true, false);
375  assert(allAtoms.size() == 0);
376 
377  logger().setLevel(save);
378 }
379 
380 namespace std {
381 
382 ostream& operator<<(ostream& out, const opencog::AtomSpace& as) {
383  list<opencog::Handle> results;
384  as.get_handles_by_type(back_inserter(results), opencog::ATOM, true);
385  for (const opencog::Handle& h : results)
386  if (h->getIncomingSetSize() == 0)
387  out << h->toString() << endl;
388  return out;
389 }
390 
391 } // namespace std
bool purge_atom(Handle h, bool recursive=false)
Definition: AtomSpace.h:261
#define createLink
Definition: Link.h:269
Handle add_node(Type t, const std::string &name="", bool async=false)
Definition: AtomSpace.cc:135
AtomSpace(const AtomSpace &)
Definition: AtomSpace.cc:70
BackingStore * backing_store
Definition: AtomSpace.h:72
std::vector< Handle > HandleSeq
a list of handles
Definition: Handle.h:246
std::shared_ptr< Atom > AtomPtr
Definition: Handle.h:48
void registerBackingStore(BackingStore *)
Definition: AtomSpace.cc:88
virtual LinkPtr getLink(Type, const HandleSeq &) const =0
Handle add(AtomPtr, bool async)
Definition: AtomTable.cc:394
AtomTable atomTable
Definition: AtomSpace.h:67
bool holds(Handle &h) const
Definition: AtomTable.h:295
AtomSpace & operator=(const AtomSpace &)
Definition: AtomSpace.cc:79
std::shared_ptr< Link > LinkPtr
Definition: Atom.h:53
AtomPtrSet extract(Handle &handle, bool recursive=true)
Definition: AtomTable.cc:667
void get_handles_by_type(HandleSeq &appendToHandles, Type type, bool subclass=false) const
Definition: AtomSpace.h:392
void unregisterBackingStore(BackingStore *)
Definition: AtomSpace.cc:93
static const Handle UNDEFINED
Definition: Handle.h:77
Handle getHandle(Type, std::string) const
Definition: AtomTable.cc:130
AttentionBank bank
Definition: AtomSpace.h:68
#define DPRINTF(...)
Definition: AtomSpace.cc:44
virtual bool ignoreType(Type t) const
Definition: BackingStore.h:105
Handle get_node(Type t, const std::string &name="")
Definition: AtomSpace.cc:155
Handle get_atom(Handle)
Definition: AtomSpace.cc:312
bool remove_atom(Handle h, bool recursive=false)
Definition: AtomSpace.cc:344
virtual HandleSeq getIncomingSet(Handle) const =0
#define createNode
Definition: Node.h:119
ostream & operator<<(ostream &out, const opencog::AtomSpace &as)
Definition: AtomSpace.cc:382
static LinkPtr LinkCast(const Handle &h)
Definition: Link.h:263
std::shared_ptr< Node > NodePtr
Definition: Node.h:112
UUID value(void) const
Definition: Handle.h:85
Handle get_link(Type t, const HandleSeq &outgoing)
Definition: AtomSpace.cc:217
virtual AtomPtr getAtom(Handle) const =0
virtual bool ignoreAtom(Handle) const
Definition: BackingStore.cc:30
unsigned short Type
type of Atoms, represented as short integer (16 bits)
Definition: types.h:40
void store_atom(Handle h)
Definition: AtomSpace.cc:245
Handle add_link(Type t, const HandleSeq &outgoing, bool async=false)
Definition: AtomSpace.cc:175
virtual NodePtr getNode(Type, const char *) const =0
Handle fetch_atom(Handle h)
Definition: AtomSpace.cc:253
virtual void storeAtom(Handle)=0
OutputIterator getHandlesByType(OutputIterator result, Type type, bool subclass=false, bool parent=true) const
Definition: AtomTable.h:204
void clear()
Clear the atomspace, remove all atoms.
Definition: AtomSpace.cc:355
Handle fetch_incoming_set(Handle, bool)
Definition: AtomSpace.cc:321
Handle add_atom(AtomPtr atom, bool async=false)
Definition: AtomSpace.cc:100