OW_IndexImpl.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2003-2004 Vintela, Inc. All rights reserved.
00003 *
00004 * Redistribution and use in source and binary forms, with or without
00005 * modification, are permitted provided that the following conditions are met:
00006 *
00007 *  - Redistributions of source code must retain the above copyright notice,
00008 *    this list of conditions and the following disclaimer.
00009 *
00010 *  - Redistributions in binary form must reproduce the above copyright notice,
00011 *    this list of conditions and the following disclaimer in the documentation
00012 *    and/or other materials provided with the distribution.
00013 *
00014 *  - Neither the name of Vintela, Inc. nor the names of its
00015 *    contributors may be used to endorse or promote products derived from this
00016 *    software without specific prior written permission.
00017 *
00018 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00019 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc. OR THE CONTRIBUTORS
00022 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028 * POSSIBILITY OF SUCH DAMAGE.
00029 *******************************************************************************/
00030 
00036 #include "OW_config.h"
00037 #include "OW_Index.hpp"
00038 #include "OW_FileSystem.hpp"
00039 #include "OW_Exception.hpp"
00040 #include "OW_Format.hpp"
00041 #include "OW_ExceptionIds.hpp"
00042 
00043 extern "C"
00044 {
00045 #ifndef OW_WIN32
00046 #include <unistd.h>
00047 #endif
00048 #include <string.h>
00049 #include <sys/types.h>
00050 #include <sys/stat.h>
00051 #include <fcntl.h>
00052 #include <errno.h>
00053 #include "db.h"
00054 }
00055 
00056 extern "C" {
00057 static int recCompare(const DBT* key1, const DBT* key2);
00058 }
00059 
00060 namespace OW_NAMESPACE
00061 {
00062 
00063 OW_DECLARE_EXCEPTION(Index);
00064 OW_DEFINE_EXCEPTION_WITH_ID(Index);
00065 
00067 class IndexImpl : public Index
00068 {
00069 public:
00070    IndexImpl();
00071    virtual ~IndexImpl();
00072    virtual void open(const char* fileName, EDuplicateKeysFlag allowDuplicates = E_NO_DUPLICATES);
00073    virtual void close();
00074    virtual IndexEntry findFirst(const char* key=NULL);
00075    virtual IndexEntry findNext();
00076    virtual IndexEntry findPrev();
00077    virtual IndexEntry find(const char* key);
00078    virtual bool add(const char* key, Int32 offset);
00079    virtual bool remove(const char* key, Int32 offset=-1L);
00080    virtual bool update(const char* key, Int32 newOffset);
00081    virtual void flush();
00082    void reopen();
00083    void openIfClosed();
00084 private:
00085    DB* m_pDB;
00086    String m_dbFileName;
00087 };
00089 // STATIC
00090 IndexRef
00091 Index::createIndexObject()
00092 {
00093    return IndexRef(new IndexImpl);
00094 }
00096 IndexImpl::IndexImpl() :
00097    m_pDB(NULL), m_dbFileName()
00098 {
00099 }
00101 IndexImpl::~IndexImpl()
00102 {
00103    try
00104    {
00105       close();
00106    }
00107    catch (...)
00108    {
00109       // don't let exceptions escape
00110    }
00111 }
00113 void
00114 IndexImpl::open(const char* fileName, EDuplicateKeysFlag allowDuplicates)
00115 {
00116    close();
00117    BTREEINFO dbinfo;
00118    m_dbFileName = fileName;
00119    m_dbFileName += ".ndx";
00120    ::memset(&dbinfo, 0, sizeof(dbinfo));
00121    dbinfo.flags = (allowDuplicates == E_ALLDUPLICATES) ? R_DUP : 0;
00122    dbinfo.compare = recCompare;
00123    if (FileSystem::canRead(m_dbFileName)
00124       && FileSystem::canWrite(m_dbFileName))
00125    {
00126 #ifdef OW_WIN32
00127       m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, _S_IREAD | _S_IWRITE,
00128          DB_BTREE, &dbinfo);
00129 #else
00130       m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, S_IRUSR | S_IWUSR,
00131          DB_BTREE, &dbinfo);
00132 #endif
00133       if (m_pDB == NULL)
00134       {
00135          OW_THROW(IndexException, Format("Failed to open index file: %1, errno =%2(%3)", m_dbFileName, errno, strerror(errno)).c_str());
00136       }
00137    }
00138    else
00139    {
00140 #ifdef OW_WIN32
00141       m_pDB = dbopen(m_dbFileName.c_str(), O_TRUNC | O_RDWR | O_CREAT,
00142          _S_IREAD | _S_IWRITE,  DB_BTREE, &dbinfo);
00143 #else
00144       m_pDB = dbopen(m_dbFileName.c_str(), O_TRUNC | O_RDWR | O_CREAT,
00145          S_IRUSR | S_IWUSR,  DB_BTREE, &dbinfo);
00146 #endif
00147       if (m_pDB == NULL)
00148       {
00149          OW_THROW(IndexException, Format("Failed to create index file: %1, errno =%2(%3)", m_dbFileName, errno, strerror(errno)).c_str());
00150       }
00151    }
00152 }
00154 void
00155 IndexImpl::reopen()
00156 {
00157    BTREEINFO dbinfo;
00158    close();
00159    ::memset(&dbinfo, 0, sizeof(dbinfo));
00160    dbinfo.compare = recCompare;
00161 #ifdef OW_WIN32
00162    m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, _S_IREAD | _S_IWRITE,
00163       DB_BTREE, &dbinfo);
00164 #else
00165    m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, S_IRUSR | S_IWUSR,
00166       DB_BTREE, &dbinfo);
00167 #endif
00168    if (m_pDB == NULL)
00169    {
00170       String msg = "Failed to re-open index file: ";
00171       msg += m_dbFileName;
00172       OW_THROW(IndexException, msg.c_str());
00173    }
00174 }
00176 void
00177 IndexImpl::openIfClosed()
00178 {
00179    if (!m_pDB)
00180    {
00181       BTREEINFO dbinfo;
00182       ::memset(&dbinfo, 0, sizeof(dbinfo));
00183       dbinfo.compare = recCompare;
00184 #ifdef OW_WIN32
00185       m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, _S_IREAD | _S_IWRITE,
00186          DB_BTREE, &dbinfo);
00187 #else
00188       m_pDB = dbopen(m_dbFileName.c_str(), O_RDWR, S_IRUSR | S_IWUSR,
00189          DB_BTREE, &dbinfo);
00190 #endif
00191       if (m_pDB == NULL)
00192       {
00193          String msg = "Failed to re-open index file: ";
00194          msg += m_dbFileName;
00195          OW_THROW(IndexException, msg.c_str());
00196       }
00197    }
00198 }
00200 void
00201 IndexImpl::close()
00202 {
00203    if (m_pDB != NULL)
00204    {
00205       m_pDB->close(m_pDB);
00206       m_pDB = NULL;
00207    }
00208 }
00210 void
00211 IndexImpl::flush()
00212 {
00213    if (m_pDB != NULL)
00214    {
00215       reopen();
00216       //m_pDB->sync(m_pDB, 0);
00217    }
00218 }
00219 namespace
00220 {
00221 class OpenCloser
00222 {
00223 public:
00224    OpenCloser(IndexImpl* pIndex) : m_pIndex(pIndex) 
00225    {
00226       m_pIndex->openIfClosed();
00227    }
00228    ~OpenCloser()
00229    {
00230       m_pIndex->close();
00231    }
00232 private:
00233    IndexImpl* m_pIndex;
00234 };
00235 }
00237 // Find exact
00238 IndexEntry
00239 IndexImpl::find(const char* key)
00240 {
00241    openIfClosed();
00242    if (m_pDB == NULL)
00243    {
00244       OW_THROW(IndexException, "Index file hasn't been opened");
00245    }
00246    DBT theKey, theRec;
00247    theKey.data = const_cast<void*>(static_cast<const void*>(key));
00248    theKey.size = ::strlen(key)+1;
00249    if (m_pDB->seq(m_pDB, &theKey, &theRec, R_CURSOR) == 0)
00250    {
00251       if (!::strcmp(reinterpret_cast<const char*>(theKey.data), key))
00252       {
00253          Int32 tmp;
00254          memcpy(&tmp, theRec.data, sizeof(tmp));
00255          return IndexEntry(reinterpret_cast<const char*>(theKey.data), tmp);
00256       }
00257    }
00258    return IndexEntry();
00259 }
00261 bool
00262 IndexImpl::add(const char* key, Int32 offset)
00263 {
00264    OpenCloser oc(this);
00265    if (m_pDB == NULL)
00266    {
00267       OW_THROW(IndexException, "Index file hasn't been opened");
00268    }
00269    DBT theRec, theKey;
00270    theRec.data = &offset;
00271    theRec.size = sizeof(offset);
00272    theKey.data = const_cast<void*>(static_cast<const void*>(key));
00273    theKey.size = ::strlen(key)+1;
00274    return (m_pDB->put(m_pDB, &theKey, &theRec, 0) == 0);
00275 }
00277 bool
00278 IndexImpl::remove(const char* key, Int32 offset)
00279 {
00280    OpenCloser oc(this);
00281    if (m_pDB == NULL)
00282    {
00283       OW_THROW(IndexException, "Index file hasn't been opened");
00284    }
00285    DBT theKey;
00286    theKey.data = const_cast<void*>(static_cast<const void*>(key));
00287    theKey.size = ::strlen(key)+1;
00288    IndexEntry ientry = findFirst(key);
00289    while (ientry)
00290    {
00291       if (!ientry.key.equals(key))
00292       {
00293          break;
00294       }
00295       if (offset == -1L || ientry.offset == offset)
00296       {
00297          return (m_pDB->del(m_pDB, &theKey, R_CURSOR) == 0);
00298       }
00299       ientry = findNext();
00300    }
00301    return false;
00302 }
00304 bool
00305 IndexImpl::update(const char* key, Int32 newOffset)
00306 {
00307    OpenCloser oc(this);
00308    if (m_pDB == NULL)
00309    {
00310       OW_THROW(IndexException, "Index file hasn't been opened");
00311    }
00312    if (!find(key))
00313    {
00314       return false;
00315    }
00316    DBT theRec, theKey;
00317    theRec.data = &newOffset;
00318    theRec.size = sizeof(newOffset);
00319    theKey.data = const_cast<void*>(static_cast<const void*>(key));
00320    theKey.size = ::strlen(key)+1;
00321    return (m_pDB->put(m_pDB, &theKey, &theRec, R_CURSOR) == 0);
00322 }
00324 IndexEntry
00325 IndexImpl::findFirst(const char* key)
00326 {
00327    openIfClosed();
00328    if (m_pDB == NULL)
00329    {
00330       OW_THROW(IndexException, "Index file hasn't been opened");
00331    }
00332    DBT theRec, theKey;
00333    memset(&theKey, 0, sizeof(theKey));
00334    memset(&theRec, 0, sizeof(theRec));
00335    int op = R_FIRST;
00336    if (key != NULL)
00337    {
00338       op = R_CURSOR;
00339       theKey.data = const_cast<void*>(static_cast<const void*>(key));
00340       theKey.size = ::strlen(key)+1;
00341    }
00342    int cc = m_pDB->seq(m_pDB, &theKey, &theRec, op);
00343    if (cc == 0)
00344    {
00345       Int32 tmp;
00346       memcpy(&tmp, theRec.data, sizeof(tmp));
00347       return IndexEntry(reinterpret_cast<const char*>(theKey.data), tmp);
00348    }
00349    return IndexEntry();
00350 }
00352 IndexEntry
00353 IndexImpl::findNext()
00354 {
00355    openIfClosed();
00356    if (m_pDB == NULL)
00357    {
00358       OW_THROW(IndexException, "Index file hasn't been opened");
00359    }
00360    DBT theRec, theKey;
00361    if (m_pDB->seq(m_pDB, &theKey, &theRec, R_NEXT) == 0)
00362    {
00363       Int32 tmp;
00364       memcpy(&tmp, theRec.data, sizeof(tmp));
00365       return IndexEntry(reinterpret_cast<const char*>(theKey.data), tmp);
00366    }
00367    return IndexEntry();
00368 }
00370 IndexEntry
00371 IndexImpl::findPrev()
00372 {
00373    openIfClosed();
00374    if (m_pDB == NULL)
00375    {
00376       OW_THROW(IndexException, "Index file hasn't been opened");
00377    }
00378    DBT theRec, theKey;
00379    if (m_pDB->seq(m_pDB, &theKey, &theRec, R_PREV) == 0)
00380    {
00381       Int32 tmp;
00382       memcpy(&tmp, theRec.data, sizeof(tmp));
00383       return IndexEntry(reinterpret_cast<const char*>(theKey.data), tmp);
00384    }
00385    return IndexEntry();
00386 }
00387 
00388 } // end namespace OW_NAMESPACE
00389 
00391 extern "C" {
00392 static int
00393 recCompare(const DBT* key1, const DBT* key2)
00394 {
00395    if (key1->data && key2->data)
00396    {
00397       return strcmp(reinterpret_cast<const char*>(key1->data), 
00398          reinterpret_cast<const char*>(key2->data));
00399    }
00400    else if (key1->data && !key2->data)
00401    {
00402       return 1;
00403    }
00404    else if (!key1->data && key2->data)
00405    {
00406       return -1;
00407    }
00408    else // key1->data == 0 && key2->data == 0
00409    {
00410       return 0;
00411    }
00412 }
00413 } // extern "C"

Generated on Thu Feb 9 08:48:00 2006 for openwbem by  doxygen 1.4.6