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

TDBDiskIndex.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/TDBDiskIndex.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;


template<class ITEM, class TAG>
00038 TDBDiskIndex<ITEM, TAG>::TDBDiskIndex(
            const std::string& pkgidx,
            const std::string& tagidx,
            Converter<ITEM, std::string>& fromitem,
            Converter<TAG, std::string>& fromtag,
            Converter<std::string, ITEM>& toitem,
            Converter<std::string, TAG>& totag,
            bool write) :
                  pkgdb(pkgidx), tagdb(tagidx),
                  fromitem(fromitem), fromtag(fromtag),
                  toitem(toitem), totag(totag)
{
      if (write)
      {
            pkgdb.open(0, O_RDWR | O_CREAT);
            tagdb.open(0, O_RDWR | O_CREAT);
      } else {
            pkgdb.open(0, O_RDONLY);
            tagdb.open(0, O_RDONLY);
      }
}

template<class ITEM, class TAG>
00061 bool TDBDiskIndex<ITEM, TAG>::hasTag(const TAG& tag) const
{
      return tagdb.has(fromtag(tag));
}

template<class ITEM, class TAG>
00067 OpSet<ITEM> TDBDiskIndex<ITEM, TAG>::getItemsHavingTag(const TAG& tag) const
{
      return toitem(tagdb.getStringSet(fromtag(tag)));
}

template<class ITEM, class TAG>
00073 OpSet<TAG> TDBDiskIndex<ITEM, TAG>::getTagsOfItem(const ITEM& item) const
{
      if (item != ITEM())
            return totag(pkgdb.getStringSet(fromitem(item)));
      else
            return OpSet<TAG>();
}

#ifndef INSTANTIATING_TEMPLATES
template<>
OpSet<string> TDBDiskIndex<string, string>::getItemsHavingTag(const string& tag) const
{
      return tagdb.getStringSet(tag);
}

template<>
OpSet<string> TDBDiskIndex<string, string>::getTagsOfItem(const string& item) const
{
      return pkgdb.getStringSet(item);
}
#endif


template<class ITEM, class TAG>
00097 int TDBDiskIndex<ITEM, TAG>::getCardinality(const TAG& tag) const
{
      return tagdb.getStringSet(fromtag(tag)).size();
}

static int collect_items(TDB_CONTEXT*, TDB_DATA key, TDB_DATA, void* data)
{
      if (key.dsize >= 1)
      {
            OpSet<string>* coll = (OpSet<string>*)data;
            (*coll) += string(key.dptr, key.dsize);
      }
      return 0;
}
static int collect_tags(TDB_CONTEXT*, TDB_DATA key, TDB_DATA, void* data)
{
      if (key.dsize >= 1)
      {
            OpSet<string>* coll = (OpSet<string>*)data;
            (*coll) += string(key.dptr, key.dsize);
      }
      return 0;
}

template<class ITEM, class TAG>
00122 OpSet<ITEM> TDBDiskIndex<ITEM, TAG>::getTaggedItems() const
{
      OpSet<string> res;
      pkgdb.traverse(collect_items, &res);
      return toitem(res);
}

template<class ITEM, class TAG>
00130 OpSet<TAG> TDBDiskIndex<ITEM, TAG>::getAllTags() const
{
      OpSet<string> res;
      tagdb.traverse(collect_tags, &res);
      return totag(res);
}

template<class ITEM, class TAG>
struct out_data
{
      Converter<std::string, ITEM>& toitem;
      Converter<std::string, TAG>& totag;
      Consumer<ITEM, TAG>& consumer;

      out_data(
                  Converter<std::string, ITEM>& toitem,
                  Converter<std::string, TAG>& totag,
                  Consumer<ITEM, TAG>& consumer) throw ()
            : toitem(toitem), totag(totag), consumer(consumer) {}
};

template<class ITEM, class TAG>
static int outputter(TDB_CONTEXT* db, TDB_DATA key, TDB_DATA val, void* data) throw ()
{
      if (key.dsize >= 1)
      {
            out_data<ITEM, TAG>* d = (out_data<ITEM, TAG>*)data;
            // Deserialize the key into a string
            string item(key.dptr, key.dsize);

            // Deserialize the tags into a string list
            OpSet<string> tags = TDBFile::deserialize_stringset(val);

            // Send the data to the consumer
            ITEM it = d->toitem(item);
            if (it != ITEM())
                  d->consumer.consume(it, d->totag(tags));
      }
      return 0;
}

template<class ITEM, class TAG>
00172 void TDBDiskIndex<ITEM, TAG>::output(Consumer<ITEM, TAG>& consumer) const
{
      out_data<ITEM, TAG> data(toitem, totag, consumer);
      pkgdb.traverse(outputter<ITEM, TAG>, &data);
}

template<class ITEM, class TAG>
00179 void TDBDiskIndex<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);

            string sitem = fromitem(i->first);
            OpSet<string> stags = fromtag(nextTags);
            OpSet<string> sprev_tags = fromtag(prevTags);

            // Set the new tagset in the item
            pkgdb.setStringSet(sitem, stags);

            // Fix the itemsets in the involved tags
            OpSet<string> t = sprev_tags - stags;
            for (OpSet<string>::const_iterator j = t.begin(); j != t.end(); j++)
            {
                  OpSet<string> items = tagdb.getStringSet(*j) - sitem;
                  if (items.empty())
                        tagdb.remove(*j);
                  else
                        tagdb.setStringSet(*j, items);
            }
            t = stags - sprev_tags;
            for (OpSet<string>::const_iterator j  = t.begin(); j != t.end(); j++)
                  tagdb.setStringSet(*j, tagdb.getStringSet(*j) + sitem);
      }
}

template<class ITEM, class TAG>
00211 void TDBDiskIndex<ITEM, TAG>::consumeItem(const ITEM& item, const OpSet<TAG>& tags)
{
      string sitem = fromitem(item);
      OpSet<string> stags = fromtag(tags);
      OpSet<string> prev_stags = pkgdb.getStringSet(sitem);

      // Add the tags to the item
      pkgdb.setStringSet(sitem, prev_stags + stags);

      // Add the item to the tags
      for (typename OpSet<string>::const_iterator i = stags.begin(); i != stags.end(); i++)
            tagdb.setStringSet(*i, tagdb.getStringSet(*i) + sitem);
}

template<class ITEM, class TAG>
00226 void TDBDiskIndex<ITEM, TAG>::consumeItems(const OpSet<ITEM>& items, const OpSet<TAG>& tags)
{
      OpSet<string> sitems = fromitem(items);
      OpSet<string> stags = fromtag(tags);

      for (typename OpSet<string>::const_iterator i = sitems.begin(); i != sitems.end(); i++)
            // Add the tags to the item
            pkgdb.setStringSet(*i, pkgdb.getStringSet(*i) + stags);

      for (typename OpSet<string>::const_iterator i = stags.begin(); i != stags.end(); i++)
            // Add the items to the tag
            tagdb.setStringSet(*i, tagdb.getStringSet(*i) + sitems);
}


#ifndef INSTANTIATING_TEMPLATES
#include <string>

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


#ifdef COMPILE_TESTSUITE

#include <tests/test-utils.h>

namespace tut {
using namespace tut_tagcoll;

struct tagcoll_tdbdiskindex_shar {
};
TESTGRP(tagcoll_tdbdiskindex);

template<> template<>
void to::test<1>()
{
      Converter<string, string> a;
      TDBDiskIndex<string, string> coll("pkgidx.test", "tagidx.test", a, a, a, a);

      test_tagged_collection(coll);

      unlink("pkgidx.test");
      unlink("tagidx.test");
}

}

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

Generated by  Doxygen 1.6.0   Back to index