Logo Search packages:      
Sourcecode: tagcoll version File versions  Download package

TDBIndexer.cc

/*
 * Fast index for tag data
 *
 * Copyright (C) 2005  Enrico Zini <enrico@debian.org>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <tagcoll/TDBIndexer.h>

#include <tdb.h>
#include <fcntl.h>      // O_RDONLY
#include <string.h>     // strlen
#include <errno.h>
#include <assert.h>

/*
#include <stdlib.h>
*/

using namespace std;
using namespace Tagcoll;


static void set_tdb(TDB_CONTEXT* db, const std::string& key, OpSet<std::string> vals) throw (SystemException)
{
      TDB_DATA k, v;
      string payload;

      k.dptr  = const_cast<char*>(key.data());
      k.dsize = key.size();

      // Serialize the string list
      for (OpSet<std::string>::const_iterator i = vals.begin(); i != vals.end(); i++)
            payload += *i + '\0';

      v.dptr = const_cast<char*>(payload.data());
      v.dsize = payload.size();

      if (tdb_store(db, k, v, TDB_REPLACE) == -1)
            throw SystemException(errno, "Writing key " + key + " to on-disk index (tdb says: " + tdb_errorstr(db) + ")");
}

template<class ITEM, class TAG>
00057 void TDBIndexer<ITEM, TAG>::writeIndex(
            Converter<ITEM, std::string>& itemconv,
            Converter<TAG, std::string>& tagconv,
            const std::string& pkgidx, const std::string& tagidx) const
{
      TDB_CONTEXT* db;

      db = tdb_open(pkgidx.c_str(), 0, 0, O_RDWR | O_CREAT, 0666);
      if (db == NULL)
                  throw SystemException(errno, "opening index file " + pkgidx);
      for (typename map<ITEM, OpSet<TAG> >::const_iterator i = items.begin();
                  i != items.end(); i++)
            set_tdb(db, itemconv(i->first), tagconv(i->second));
      tdb_close(db);

      db = tdb_open(tagidx.c_str(), 0, 0, O_RDWR | O_CREAT, 0666);
      if (db == NULL)
                  throw SystemException(errno, "opening index file " + tagidx);
      for (typename map<TAG, OpSet<ITEM> >::const_iterator i = tags.begin();
                  i != tags.end(); i++)
            set_tdb(db, tagconv(i->first), itemconv(i->second));

      tdb_close(db);
}


template<class ITEM, class TAG>
00084 OpSet<ITEM> TDBIndexer<ITEM, TAG>::getItemsHavingTag(const TAG& tag) const
{
      typename map<TAG, OpSet<ITEM> >::const_iterator i = tags.find(tag);
      if (i != tags.end())
            return i->second;
      else
            return OpSet<ITEM>();
}

template<class ITEM, class TAG>
00094 OpSet<TAG> TDBIndexer<ITEM, TAG>::getTagsOfItem(const ITEM& item) const
{
      typename map<ITEM, OpSet<TAG> >::const_iterator i = items.find(item);
      if (i != items.end())
            return i->second;
      else
            return OpSet<TAG>();
}

template<class ITEM, class TAG>
00104 OpSet<ITEM> TDBIndexer<ITEM, TAG>::getTaggedItems() const
{
      OpSet<ITEM> res;
      for (typename map<ITEM, OpSet<TAG> >::const_iterator i = items.begin();
                  i != items.end(); i++)
            res += i->first;
      return res;
}

template<class ITEM, class TAG>
00114 OpSet<TAG> TDBIndexer<ITEM, TAG>::getAllTags() const
{
      OpSet<TAG> res;
      for (typename map<TAG, OpSet<ITEM> >::const_iterator i = tags.begin();
                  i != tags.end(); i++)
            res += i->first;
      return res;
}

template<class ITEM, class TAG>
00124 void TDBIndexer<ITEM, TAG>::output(Consumer<ITEM, TAG>& consumer) const
{
      for (typename map<ITEM, OpSet<TAG> >::const_iterator i = items.begin();
                  i != items.end(); i++)
            consumer.consume(i->first, i->second);
}

template<class ITEM, class TAG>
00132 void TDBIndexer<ITEM, TAG>::applyChange(const PatchList<ITEM, TAG>& change)
{
      for (typename PatchList<ITEM, TAG>::const_iterator i = change.begin(); i != change.end(); i++)
      {
            // Save the previous tagset in `rev'
            OpSet<TAG> prevTags = getTags(i->first);
            OpSet<TAG> nextTags = i->second.apply(prevTags);

            // Set the new tagset in the item
            items[i->first] = nextTags;

            // Fix the itemsets in the involved tags
            OpSet<TAG> t = prevTags - nextTags;
            for (typename OpSet<TAG>::const_iterator j = t.begin(); j != t.end(); j++)
            {
                  OpSet<TAG> items = getItems(*j) - i->first;
                  if (items.empty())
                        tags.erase(*j);
                  else
                        tags[*j] = items;
            }
            t = nextTags - prevTags;
            for (typename OpSet<TAG>::const_iterator j  = t.begin(); j != t.end(); j++)
                  tags[*j] += i->first;
      }
}


template<class ITEM, class TAG>
00161 void TDBIndexer<ITEM, TAG>::consumeItem(const ITEM& item, const OpSet<TAG>& tags)
{
      // Add the tags to the item
      items[item] += tags;

      // Add the item to the tags
      for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++)
            this->tags[*i] += item;
}

template<class ITEM, class TAG>
00172 void TDBIndexer<ITEM, TAG>::consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
{
      for (typename OpSet<ITEM>::const_iterator i = items.begin(); i != items.end(); i++)
            // Add the tags to the item
            this->items[*i] += tags;

      for (typename OpSet<TAG>::const_iterator i = tags.begin(); i != tags.end(); i++)
            // Add the items to the tag
            this->tags[*i] += items;
}

#ifndef INSTANTIATING_TEMPLATES
#include <string>

namespace Tagcoll {
      template class TDBIndexer<std::string, std::string>;
}
#endif

#ifdef COMPILE_TESTSUITE

#include <tests/test-utils.h>

namespace tut {
using namespace tut_tagcoll;

struct tagcoll_tdbindexer_shar {
};
TESTGRP(tagcoll_tdbindexer);

template<> template<>
void to::test<1>()
{
      TDBIndexer<string, string> coll;

      test_tagged_collection(coll);
}

}

#endif
// vim:set ts=4 sw=4:

Generated by  Doxygen 1.6.0   Back to index