diff options
author | Bernard Normier <bernard@zeroc.com> | 2005-11-08 00:13:52 +0000 |
---|---|---|
committer | Bernard Normier <bernard@zeroc.com> | 2005-11-08 00:13:52 +0000 |
commit | 20c342c1c5f35fbe60565dee7fb81ca2baf04e5b (patch) | |
tree | 199faf2102026478de9a1e55f6fff271591e7b98 /cpp | |
parent | fixed bi-dir/shutdown deadlock (diff) | |
download | ice-20c342c1c5f35fbe60565dee7fb81ca2baf04e5b.tar.bz2 ice-20c342c1c5f35fbe60565dee7fb81ca2baf04e5b.tar.xz ice-20c342c1c5f35fbe60565dee7fb81ca2baf04e5b.zip |
Implemented enhancement 415 (Freeze Map compare functors)
Diffstat (limited to 'cpp')
-rw-r--r-- | cpp/CHANGES | 34 | ||||
-rw-r--r-- | cpp/include/Freeze/Map.h | 305 | ||||
-rw-r--r-- | cpp/src/Freeze/MapI.cpp | 287 | ||||
-rw-r--r-- | cpp/src/Freeze/MapI.h | 19 | ||||
-rw-r--r-- | cpp/src/Freeze/SharedDb.cpp | 29 | ||||
-rw-r--r-- | cpp/src/Freeze/SharedDb.h | 23 | ||||
-rw-r--r-- | cpp/src/slice2freeze/Main.cpp | 422 | ||||
-rw-r--r-- | cpp/test/Freeze/dbmap/Client.cpp | 110 | ||||
-rw-r--r-- | cpp/test/Freeze/dbmap/Makefile | 8 | ||||
-rw-r--r-- | cpp/test/Freeze/dbmap/dbmap.dsp | 24 |
10 files changed, 1113 insertions, 148 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES index 2f0e00ef88a..7e2a954f5c5 100644 --- a/cpp/CHANGES +++ b/cpp/CHANGES @@ -1,18 +1,38 @@ Changes since version 2.1.2 --------------------------- +- Added custom-compare to Freeze Maps: + you can now provide your own compare functors for keys and indices. See + the slice2freeze usage for the new options. The default compare uses + compares binary strings encoded using the Ice encoding (like in previous + releases). + Map have 4 new functions: + - lower_bound (const and non-const) + - upper_bound (const and non-const) + In addition, the implementation of equal_range is now correct. + + Generated index classes have 6 new functions: + - lowerBoundFor<name> (const and non-const) + - upperBoundFor<name> (const and non-const) + - equalRangeFor<name> (const and non-const) + The findBy<name> also takes a new bool parameter, "onlyDups"; its default + value is true for compatibility with previous releases. When onlyDups is + true, findBy<name> returns only the elements that match the given index + value; when false, the iterator returns first these elements and then + lets you iterate over the remainder of the database (according to the order + defined by the index). + - Fixed a deadlock during shutdown that could happen with bi-directional connections. - Removed ice_default() method from proxies. -- Added downgrade() to IceUtil::RWRecMutex and fixed a bug in - upgrade(): previously, upgrade() was equivalent to calling unlock() - followed by writeLock(), which could allow a thread to acquire a - write lock while another thread was in the middle an - upgrade. upgrade() is now atomic, so whatever state is protected by - a read lock is guaranteed to be still unchanged when upgrade() - completes. +- Added downgrade() to IceUtil::RWRecMutex and fixed a bug in upgrade(): + previously, upgrade() was equivalent to calling unlock() followed + by writeLock(), which could allow a thread to acquire a write lock while + another thread was in the middle an upgrade. upgrade() is now atomic, so + whatever state is protected by a read lock is guaranteed to be still + unchanged when upgrade() completes. - Connection::close(false) (i.e., graceful connection shutdown) now waits until all outstanding requests have completed. diff --git a/cpp/include/Freeze/Map.h b/cpp/include/Freeze/Map.h index a489af84fb8..365e2a03af2 100644 --- a/cpp/include/Freeze/Map.h +++ b/cpp/include/Freeze/Map.h @@ -32,7 +32,21 @@ class MapHelperI; class IteratorHelperI; class SharedDb; -class FREEZE_API MapIndexBase : public IceUtil::Shared +class FREEZE_API KeyCompareBase : public IceUtil::Shared +{ +public: + KeyCompareBase(bool); + + bool compareEnabled() const; + + virtual int compare(const Key&, const Key&) = 0; + +private: + const bool _enabled; +}; +typedef IceUtil::Handle<KeyCompareBase> KeyCompareBasePtr; + +class FREEZE_API MapIndexBase : public KeyCompareBase { public: @@ -40,7 +54,10 @@ public: const std::string& name() const; - IteratorHelper* untypedFind(const Key&, bool) const; + IteratorHelper* untypedFind(const Key&, bool, bool) const; + IteratorHelper* untypedLowerBound(const Key&, bool) const; + IteratorHelper* untypedUpperBound(const Key&, bool) const; + int untypedCount(const Key&) const; // @@ -50,7 +67,7 @@ public: protected: - MapIndexBase(const std::string&); + MapIndexBase(const std::string&, bool); Ice::CommunicatorPtr _communicator; @@ -63,11 +80,10 @@ private: std::string _name; MapIndexI* _impl; const MapHelperI* _map; + const KeyCompareBasePtr _keyCompare; }; - typedef IceUtil::Handle<MapIndexBase> MapIndexBasePtr; - class FREEZE_API MapHelper { public: @@ -77,6 +93,7 @@ public: const std::string& dbName, const std::string& key, const std::string& value, + const KeyCompareBasePtr&, const std::vector<MapIndexBasePtr>&, bool createDb); @@ -85,6 +102,12 @@ public: virtual IteratorHelper* find(const Key&, bool) const = 0; + virtual IteratorHelper* + lowerBound(const Key&, bool) const = 0; + + virtual IteratorHelper* + upperBound(const Key&, bool) const = 0; + virtual void put(const Key&, const Value&) = 0; @@ -144,9 +167,11 @@ public: // // Forward declaration // -template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec> +template <typename key_type, typename mapped_type, + typename KeyCodec, typename ValueCodec, typename Compare> class Map; -template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec> +template <typename key_type, typename mapped_type, + typename KeyCodec, typename ValueCodec, typename Compare> class ConstIterator; // @@ -168,7 +193,8 @@ struct IteratorBase // TODO: It's possible to implement bidirectional iterators, if // necessary. // -template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec> +template<typename key_type, typename mapped_type, + typename KeyCodec, typename ValueCodec, typename Compare> class Iterator : public IteratorBase { public: @@ -344,8 +370,10 @@ private: ValueCodec::read(value, *v, _communicator); } - friend class ConstIterator<key_type, mapped_type, KeyCodec, ValueCodec>; - friend class Map<key_type, mapped_type, KeyCodec, ValueCodec>; + friend class ConstIterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>; + friend class Map<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>; std::auto_ptr<IteratorHelper> _helper; Ice::CommunicatorPtr _communicator; @@ -367,7 +395,8 @@ private: // // See Iterator comments for design notes // -template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec> +template <typename key_type, typename mapped_type, + typename KeyCodec, typename ValueCodec, typename Compare> class ConstIterator : public IteratorBase { public: @@ -413,7 +442,8 @@ public: // A Iterator can be converted to a ConstIterator (but not // vice versa) - same for operator=. // - ConstIterator(const Iterator<key_type, mapped_type, KeyCodec, ValueCodec>& rhs) : + ConstIterator(const Iterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>& rhs) : _refValid(false) { if(rhs._helper.get() != 0) @@ -445,7 +475,8 @@ public: // // Create const_iterator from iterator. // - ConstIterator& operator=(const Iterator<key_type, mapped_type, KeyCodec, ValueCodec>& rhs) + ConstIterator& operator=(const Iterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>& rhs) { if(rhs._helper.get() != 0) { @@ -563,7 +594,8 @@ private: ValueCodec::read(value, *v, _communicator); } - friend class Map<key_type, mapped_type, KeyCodec, ValueCodec>; + friend class Map<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>; std::auto_ptr<IteratorHelper> _helper; Ice::CommunicatorPtr _communicator; @@ -583,6 +615,161 @@ private: mutable bool _refValid; }; +#if defined(_MSC_VER) && (_MSC_VER <= 1300) +// +// Without partial template specialization +// +struct IceEncodingCompare +{ + bool operator()(...) + { + return false; + } +}; + +template<typename Compare> +inline bool +enableKeyCompare(const Compare&) +{ + return true; +} + +template<> +inline bool +enableKeyCompare<IceEncodingCompare>(const IceEncodingCompare&) +{ + return false; +} +# else +struct IceEncodingCompare {}; +#endif + +template<typename key_type, typename KeyCodec, typename Compare> +class KeyCompare : public KeyCompareBase +{ +public: + KeyCompare(const Compare& compare, + const Ice::CommunicatorPtr& communicator) : +#if defined(_MSC_VER) && (_MSC_VER <= 1300) + KeyCompareBase(enableKeyCompare(compare)), +#else + KeyCompareBase(true), +#endif + _compare(compare), + _communicator(communicator) + {} + + virtual int compare(const Key& dbKey1, const Key& dbKey2) + { + key_type key1; + KeyCodec::read(key1, dbKey1, _communicator); + key_type key2; + KeyCodec::read(key2, dbKey2, _communicator); + + if(_compare(key1, key2)) + { + return -1; + } + else if(_compare(key2, key1)) + { + return 1; + } + else + { + return 0; + } + } +private: + Compare _compare; + Ice::CommunicatorPtr _communicator; +}; + +#if !defined(_MSC_VER) || (_MSC_VER >= 1300) +// +// Partial template specialization: +// do nothing for the IceEncodingCompare comparator +// +template<typename key_type, typename KeyCodec> +class KeyCompare<key_type, KeyCodec, IceEncodingCompare> : public KeyCompareBase +{ +public: + KeyCompare(const IceEncodingCompare&, const Ice::CommunicatorPtr&): + KeyCompareBase(false) + {} + + virtual int compare(const Key& dbKey1, const Key& dbKey2) + { + assert(0); + return 0; + } +}; +#endif + +// +// Need to separate MapIndex template class because _communicator is +// set later +// +template<typename key_type, typename KeyCodec, typename Compare> +class MapIndex : public MapIndexBase +{ +public: + virtual int compare(const Key& dbKey1, const Key& dbKey2) + { + key_type key1; + KeyCodec::read(key1, dbKey1, _communicator); + key_type key2; + KeyCodec::read(key2, dbKey2, _communicator); + + if(_compare(key1, key2)) + { + return -1; + } + else if(_compare(key2, key1)) + { + return 1; + } + else + { + return 0; + } + } + +protected: + MapIndex(const std::string& name, const Compare& compare) : +#if defined(_MSC_VER) && (_MSC_VER <= 1300) + MapIndexBase(name, enableKeyCompare(compare)), +#else + MapIndexBase(name, true), +#endif + _compare(compare) + {} + +private: + Compare _compare; +}; + +#if !defined(_MSC_VER) || (_MSC_VER >= 1300) +// +// Partial template specialization: +// do nothing for the IceEncodingCompare comparator +// +template<typename key_type, typename KeyCodec> +class MapIndex<key_type, KeyCodec, IceEncodingCompare> : public MapIndexBase +{ +public: + virtual int compare(const Key& dbKey1, const Key& dbKey2) + { + assert(0); + return 0; + } + +protected: + MapIndex(const std::string& name, const IceEncodingCompare&): + MapIndexBase(name, false) + {} +}; +#endif + // // This is an STL container that matches the requirements of a // Associated Container - with the restriction that operator[] isn't @@ -593,7 +780,9 @@ private: // TODO: If necessary it would be possible to implement reverse and // bidirectional iterators. // -template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec> +template<typename key_type, typename mapped_type, + typename KeyCodec, typename ValueCodec, + typename Compare = IceEncodingCompare> class Map { public: @@ -606,14 +795,15 @@ public: // hasher, key_equal, key_compare, value_compare // - typedef Iterator<key_type, mapped_type, KeyCodec, ValueCodec > iterator; - typedef ConstIterator<key_type, mapped_type, KeyCodec, ValueCodec > const_iterator; + typedef Iterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare> iterator; + typedef ConstIterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare> const_iterator; // // No definition for reference, const_reference, pointer or // const_pointer. // - typedef size_t size_type; typedef ptrdiff_t difference_type; @@ -627,27 +817,36 @@ public: // Constructors // Map(const Freeze::ConnectionPtr& connection, - const std::string& dbName, - bool createDb = true) : + const std::string& dbName, + bool createDb = true, + const Compare& compare = Compare()) : _communicator(connection->getCommunicator()) - { + { + KeyCompareBasePtr keyCompare = + new KeyCompare<key_type, KeyCodec, Compare>(compare, _communicator); std::vector<MapIndexBasePtr> indices; + _helper.reset(MapHelper::create(connection, dbName, - KeyCodec::typeId(), ValueCodec::typeId(), - indices, createDb)); + KeyCodec::typeId(), ValueCodec::typeId(), + keyCompare, indices, createDb)); } - template <class _InputIterator> + template<class _InputIterator> Map(const Freeze::ConnectionPtr& connection, const std::string& dbName, bool createDb, - _InputIterator first, _InputIterator last) : + _InputIterator first, _InputIterator last, + const Compare& compare = Compare()) : _communicator(connection->getCommunicator()) { + KeyCompareBasePtr keyCompare = + new KeyCompare<key_type, KeyCodec, Compare>(compare, _communicator); + std::vector<MapIndexBasePtr> indices; + _helper.reset(MapHelper::create(connection, dbName, KeyCodec::typeId(), ValueCodec::typeId(), - indices, createDb)); + keyCompare, indices, createDb)); while(first != last) { put(*first); @@ -916,16 +1115,47 @@ public: } + iterator lower_bound(const key_type& key) + { + Key k; + KeyCodec::write(key, k, _communicator); + + return iterator(_helper->lowerBound(k, false), _communicator); + } + + const_iterator lower_bound(const key_type& key) const + { + Key k; + KeyCodec::write(key, k, _communicator); + + return iterator(_helper->lowerBound(k, true), _communicator); + } + + iterator upper_bound(const key_type& key) + { + Key k; + KeyCodec::write(key, k, _communicator); + + return iterator(_helper->upperBound(k, false), _communicator); + } + + const_iterator upper_bound(const key_type& key) const + { + Key k; + KeyCodec::write(key, k, _communicator); + + return iterator(_helper->upperBound(k, true), _communicator); + } + std::pair<iterator, iterator> equal_range(const key_type& key) { - iterator p = find(key); - return std::pair<iterator,iterator>(p,p); + return std::make_pair(lower_bound(key), upper_bound(key)); } - std::pair<const_iterator, const_iterator> equal_range(const key_type& key) const + std::pair<const_iterator, const_iterator> + equal_range(const key_type& key) const { - const_iterator p = find(key); - return std::pair<const_iterator,const_iterator>(p,p); + return std::make_pair(lower_bound(key), upper_bound(key)); } const Ice::CommunicatorPtr& @@ -934,7 +1164,6 @@ public: return _communicator(); } - protected: Map(const Ice::CommunicatorPtr& communicator) : @@ -957,16 +1186,20 @@ namespace std { // TODO: update. -template <class key_type, class mapped_type, class KeyCodec, class ValueCodec> +template <class key_type, class mapped_type, + class KeyCodec, class ValueCodec, class Compare> inline pair<const key_type, const mapped_type>* -value_type(const Freeze::Iterator<key_type, mapped_type, KeyCodec, ValueCodec>&) +value_type(const Freeze::Iterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>&) { return (pair<const key_type, const mapped_type>*)0; } -template <class key_type, class mapped_type, class KeyCodec, class ValueCodec> +template <class key_type, class mapped_type, + class KeyCodec, class ValueCodec, class Compare> inline pair<const key_type, const mapped_type>* -value_type(const Freeze::ConstIterator<key_type, mapped_type, KeyCodec, ValueCodec>&) +value_type(const Freeze::ConstIterator<key_type, mapped_type, + KeyCodec, ValueCodec, Compare>&) { return (pair<const key_type, const mapped_type>*)0; } diff --git a/cpp/src/Freeze/MapI.cpp b/cpp/src/Freeze/MapI.cpp index f9473110012..065a48c1fa0 100644 --- a/cpp/src/Freeze/MapI.cpp +++ b/cpp/src/Freeze/MapI.cpp @@ -27,7 +27,10 @@ Freeze::MapIndexBase::~MapIndexBase() { } -Freeze::MapIndexBase::MapIndexBase(const string& name) : +Freeze::MapIndexBase::MapIndexBase( + const string& name, + bool enabled) : + KeyCompareBase(enabled), _name(name), _impl(0), _map(0) @@ -41,9 +44,21 @@ MapIndexBase::name() const } IteratorHelper* -Freeze::MapIndexBase::untypedFind(const Key& k, bool ro) const +Freeze::MapIndexBase::untypedFind(const Key& k, bool ro, bool onlyDups) const { - return _impl->untypedFind(k, ro, *_map); + return _impl->untypedFind(k, ro, *_map, onlyDups); +} + +IteratorHelper* +Freeze::MapIndexBase::untypedLowerBound(const Key& k, bool ro) const +{ + return _impl->untypedLowerBound(k, ro, *_map); +} + +IteratorHelper* +Freeze::MapIndexBase::untypedUpperBound(const Key& k, bool ro) const +{ + return _impl->untypedUpperBound(k, ro, *_map); } int @@ -53,6 +68,19 @@ Freeze::MapIndexBase::untypedCount(const Key& k) const } // +// KeyCompareBase +// +Freeze::KeyCompareBase::KeyCompareBase(bool enabled) : + _enabled(enabled) +{} + +bool +Freeze::KeyCompareBase::compareEnabled() const +{ + return _enabled; +} + +// // MapHelper (from Map.h) // @@ -61,11 +89,12 @@ Freeze::MapHelper::create(const Freeze::ConnectionPtr& connection, const string& dbName, const string& key, const string& value, + const Freeze::KeyCompareBasePtr& keyCompare, const std::vector<MapIndexBasePtr>& indices, bool createDb) { Freeze::ConnectionIPtr connectionI = Freeze::ConnectionIPtr::dynamicCast(connection); - return new MapHelperI(connectionI, dbName, key, value, indices, createDb); + return new MapHelperI(connectionI, dbName, key, value, keyCompare, indices, createDb); } Freeze::MapHelper::~MapHelper() @@ -82,7 +111,8 @@ Freeze::IteratorHelper::create(const MapHelper& m, bool readOnly) { const MapHelperI& actualMap = dynamic_cast<const MapHelperI&>(m); - auto_ptr<IteratorHelperI> r(new IteratorHelperI(actualMap, readOnly, 0)); + auto_ptr<IteratorHelperI> r(new IteratorHelperI(actualMap, readOnly, + 0, false)); if(r->next()) { return r.release(); @@ -104,11 +134,13 @@ Freeze::IteratorHelper::~IteratorHelper() // Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly, - const MapIndexBasePtr& index) : + const MapIndexBasePtr& index, + bool onlyDups) : _map(m), _dbc(0), _indexed(index != 0), - _tx(0) + _tx(0), + _onlyDups(onlyDups) { if(_map._trace >= 2) { @@ -157,7 +189,8 @@ Freeze::IteratorHelperI::IteratorHelperI(const IteratorHelperI& it) : _map(it._map), _dbc(0), _indexed(it._indexed), - _tx(0) + _tx(0), + _onlyDups(it._onlyDups) { if(_map._trace >= 2) { @@ -228,6 +261,85 @@ Freeze::IteratorHelperI::find(const Key& key) const } } +bool +Freeze::IteratorHelperI::lowerBound(const Key& key) const +{ + // + // We retrieve the action key for upperBound + // + Dbt dbKey; + _key = key; + initializeOutDbt(_key, dbKey); + dbKey.set_size(static_cast<u_int32_t>(_key.size())); + + // + // Keep 0 length since we're not interested in the data + // + Dbt dbValue; + dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); + + for(;;) + { + try + { + int err = _dbc->get(&dbKey, &dbValue, DB_SET_RANGE); + if(err == 0) + { + _key.resize(dbKey.get_size()); + return true; + } + else if(err == DB_NOTFOUND) + { + return false; + } + else + { + // + // Bug in Freeze + // + assert(0); + throw DatabaseException(__FILE__, __LINE__); + } + } + catch(const ::DbDeadlockException& dx) + { + if(_tx != 0) + { + _tx->dead(); + } + + DeadlockException ex(__FILE__, __LINE__); + ex.message = dx.what(); + throw ex; + } + catch(const ::DbException& dx) + { + handleDbException(dx, _key, dbKey, __FILE__, __LINE__); + } + } +} + +bool +Freeze::IteratorHelperI::upperBound(const Key& key) const +{ + if(lowerBound(key)) + { + if(_key == key) + { + return next(true); + } + else + { + return true; + } + } + else + { + return false; + } +} + + Freeze::IteratorHelper* Freeze::IteratorHelperI::clone() const { @@ -478,9 +590,15 @@ Freeze::IteratorHelperI::erase() } } -bool +bool Freeze::IteratorHelperI::next() const { + return next(false); +} + +bool +Freeze::IteratorHelperI::next(bool skipDups) const +{ // // Keep 0 length since we're not interested in the data // @@ -489,7 +607,15 @@ Freeze::IteratorHelperI::next() const Dbt dbValue; dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL); - int flags = _indexed ? DB_NEXT_DUP : DB_NEXT; + int flags = DB_NEXT; + if(skipDups) + { + flags = DB_NEXT_NODUP; + } + else if(_indexed && _onlyDups) + { + flags = DB_NEXT_DUP; + } try { @@ -660,10 +786,11 @@ Freeze::MapHelperI::MapHelperI(const ConnectionIPtr& connection, const string& dbName, const string& key, const string& value, + const KeyCompareBasePtr& keyCompare, const vector<MapIndexBasePtr>& indices, bool createDb) : _connection(connection), - _db(SharedDb::get(connection, dbName, key, value, indices, createDb)), + _db(SharedDb::get(connection, dbName, key, value, keyCompare, indices, createDb)), _dbName(dbName), _trace(connection->trace()) { @@ -698,7 +825,7 @@ Freeze::MapHelperI::find(const Key& k, bool readOnly) const { try { - auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0)); + auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0, false)); if(r->find(k)) { return r.release(); @@ -731,6 +858,86 @@ Freeze::MapHelperI::find(const Key& k, bool readOnly) const } } +Freeze::IteratorHelper* +Freeze::MapHelperI::lowerBound(const Key& k, bool readOnly) const +{ + for(;;) + { + try + { + auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0, false)); + if(r->lowerBound(k)) + { + return r.release(); + } + else + { + return 0; + } + } + catch(const DeadlockException&) + { + if(_connection->dbTxn() != 0) + { + throw; + } + else + { + if(_connection->deadlockWarning()) + { + Warning out(_connection->communicator()->getLogger()); + out << "Deadlock in Freeze::MapHelperI::lowerBound on Map \"" + << _dbName << "\"; retrying ..."; + } + + // + // Ignored, try again + // + } + } + } +} + +Freeze::IteratorHelper* +Freeze::MapHelperI::upperBound(const Key& k, bool readOnly) const +{ + for(;;) + { + try + { + auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0, false)); + if(r->upperBound(k)) + { + return r.release(); + } + else + { + return 0; + } + } + catch(const DeadlockException&) + { + if(_connection->dbTxn() != 0) + { + throw; + } + else + { + if(_connection->deadlockWarning()) + { + Warning out(_connection->communicator()->getLogger()); + out << "Deadlock in Freeze::MapHelperI::upperBound on Map \"" + << _dbName << "\"; retrying ..."; + } + + // + // Ignored, try again + // + } + } + } +} + void Freeze::MapHelperI::put(const Key& key, const Value& value) { @@ -1144,6 +1351,20 @@ Freeze::MapHelperI::closeAllIteratorsExcept(const IteratorHelperI::TxPtr& tx) co // MapIndexI // +extern "C" +{ +static int customIndexCompare(DB* db, const DBT* dbt1, const DBT* dbt2) +{ + MapIndexI* me = static_cast<MapIndexI*>(db->app_private); + Byte* first = static_cast<Byte*>(dbt1->data); + Key k1(first, first + dbt1->size); + first = static_cast<Byte*>(dbt2->data); + Key k2(first, first + dbt2->size); + + return me->getKeyCompare()->compare(k1, k2); +} +} + static int callback(Db* secondary, const Dbt* key, const Dbt* value, Dbt* result) { @@ -1172,6 +1393,13 @@ Freeze::MapIndexI::MapIndexI(const ConnectionIPtr& connection, SharedDb& db, _dbName = db.dbName() + "." + _index->name(); + _db->set_app_private(this); + + if(index->compareEnabled()) + { + _db->set_bt_compare(&customIndexCompare); + } + _db->open(txn, _dbName.c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE); // @@ -1191,9 +1419,10 @@ Freeze::MapIndexI::~MapIndexI() } IteratorHelper* -Freeze::MapIndexI::untypedFind(const Key& k, bool ro, const MapHelperI& m) const +Freeze::MapIndexI::untypedFind(const Key& k, bool ro, const MapHelperI& m, + bool onlyDups) const { - auto_ptr<IteratorHelperI> r(new IteratorHelperI(m, ro, _index)); + auto_ptr<IteratorHelperI> r(new IteratorHelperI(m, ro, _index, onlyDups)); if(r->find(k)) { @@ -1205,6 +1434,36 @@ Freeze::MapIndexI::untypedFind(const Key& k, bool ro, const MapHelperI& m) const } } +IteratorHelper* +Freeze::MapIndexI::untypedLowerBound(const Key& k, bool ro, const MapHelperI& m) const +{ + auto_ptr<IteratorHelperI> r(new IteratorHelperI(m, ro, _index, false)); + + if(r->lowerBound(k)) + { + return r.release(); + } + else + { + return 0; + } +} + +IteratorHelper* +Freeze::MapIndexI::untypedUpperBound(const Key& k, bool ro, const MapHelperI& m) const +{ + auto_ptr<IteratorHelperI> r(new IteratorHelperI(m, ro, _index, false)); + + if(r->upperBound(k)) + { + return r.release(); + } + else + { + return 0; + } +} + int Freeze::MapIndexI::untypedCount(const Key& k, const ConnectionIPtr& connection) const { diff --git a/cpp/src/Freeze/MapI.h b/cpp/src/Freeze/MapI.h index 5a1a1d9d9a0..8f842926a47 100644 --- a/cpp/src/Freeze/MapI.h +++ b/cpp/src/Freeze/MapI.h @@ -23,7 +23,8 @@ class IteratorHelperI : public IteratorHelper { public: - IteratorHelperI(const MapHelperI& m, bool readOnly, const MapIndexBasePtr& index); + IteratorHelperI(const MapHelperI& m, bool readOnly, + const MapIndexBasePtr& index, bool onlyDups); IteratorHelperI(const IteratorHelperI&); virtual @@ -32,6 +33,12 @@ public: bool find(const Key& k) const; + bool + lowerBound(const Key& k) const; + + bool + upperBound(const Key& k) const; + virtual IteratorHelper* clone() const; @@ -50,6 +57,8 @@ public: virtual bool next() const; + bool next(bool) const; + void close(); @@ -86,6 +95,7 @@ private: const MapHelperI& _map; Dbc* _dbc; const bool _indexed; + const bool _onlyDups; TxPtr _tx; mutable Key _key; @@ -99,6 +109,7 @@ public: MapHelperI(const ConnectionIPtr&, const std::string&, const std::string&, const std::string&, + const KeyCompareBasePtr&, const std::vector<MapIndexBasePtr>&, bool); virtual ~MapHelperI(); @@ -106,6 +117,12 @@ public: virtual IteratorHelper* find(const Key&, bool) const; + virtual IteratorHelper* + lowerBound(const Key&, bool) const; + + virtual IteratorHelper* + upperBound(const Key&, bool) const; + virtual void put(const Key&, const Value&); diff --git a/cpp/src/Freeze/SharedDb.cpp b/cpp/src/Freeze/SharedDb.cpp index 4e1c490f585..8cfd9feb1a3 100644 --- a/cpp/src/Freeze/SharedDb.cpp +++ b/cpp/src/Freeze/SharedDb.cpp @@ -44,6 +44,20 @@ checkTypes(const SharedDb& sharedDb, const string& key, const string& value) } } +extern "C" +{ +static int customCompare(DB* db, const DBT* dbt1, const DBT* dbt2) +{ + SharedDb* me = static_cast<SharedDb*>(db->app_private); + Byte* first = static_cast<Byte*>(dbt1->data); + Key k1(first, first + dbt1->size); + first = static_cast<Byte*>(dbt2->data); + Key k2(first, first + dbt2->size); + + return me->getKeyCompare()->compare(k1, k2); +} +} + Freeze::SharedDb::SharedDbMap* Freeze::SharedDb::sharedDbMap = 0; const string& @@ -57,6 +71,7 @@ Freeze::SharedDb::get(const ConnectionIPtr& connection, const string& dbName, const string& key, const string& value, + const KeyCompareBasePtr& keyCompare, const vector<MapIndexBasePtr>& indices, bool createDb) { @@ -96,7 +111,8 @@ Freeze::SharedDb::get(const ConnectionIPtr& connection, // // MapKey not found, let's create and open a new Db // - auto_ptr<SharedDb> result(new SharedDb(mapKey, key, value, connection, indices, createDb)); + auto_ptr<SharedDb> result(new SharedDb(mapKey, key, value, connection, + keyCompare, indices, createDb)); // // Insert it into the map @@ -221,10 +237,12 @@ Freeze::SharedDb::SharedDb(const MapKey& mapKey, const string& key, const string& value, const ConnectionIPtr& connection, + const KeyCompareBasePtr& keyCompare, const vector<MapIndexBasePtr>& indices, bool createDb) : Db(connection->dbEnv()->getEnv(), 0), _mapKey(mapKey), + _keyCompare(keyCompare), _refCount(0), _trace(connection->trace()) { @@ -234,7 +252,8 @@ Freeze::SharedDb::SharedDb(const MapKey& mapKey, out << "opening Db \"" << _mapKey.dbName << "\""; } - ConnectionPtr catalogConnection = createConnection(_mapKey.communicator, connection->dbEnv()->getEnvName()); + ConnectionPtr catalogConnection = + createConnection(_mapKey.communicator, connection->dbEnv()->getEnvName()); Catalog catalog(catalogConnection, _catalogName); Catalog::iterator ci = catalog.find(_mapKey.dbName); @@ -258,6 +277,12 @@ Freeze::SharedDb::SharedDb(const MapKey& mapKey, _value = value; } + set_app_private(this); + if(_keyCompare->compareEnabled()) + { + set_bt_compare(&customCompare); + } + try { TransactionPtr tx = catalogConnection->beginTransaction(); diff --git a/cpp/src/Freeze/SharedDb.h b/cpp/src/Freeze/SharedDb.h index c51dcb45983..dd881f74725 100644 --- a/cpp/src/Freeze/SharedDb.h +++ b/cpp/src/Freeze/SharedDb.h @@ -34,7 +34,10 @@ public: ~MapIndexI(); - IteratorHelper* untypedFind(const Key&, bool, const MapHelperI&) const; + IteratorHelper* untypedFind(const Key&, bool, const MapHelperI&, bool) const; + IteratorHelper* untypedLowerBound(const Key&, bool, const MapHelperI&) const; + IteratorHelper* untypedUpperBound(const Key&, bool, const MapHelperI&) const; + int untypedCount(const Key&, const ConnectionIPtr&) const; int @@ -50,6 +53,11 @@ public: return _db.get(); } + const MapIndexBasePtr& getKeyCompare() const + { + return _index; + } + private: const MapIndexBasePtr _index; @@ -66,6 +74,7 @@ public: static SharedDbPtr get(const ConnectionIPtr&, const std::string&, const std::string&, const std::string&, + const KeyCompareBasePtr&, const std::vector<MapIndexBasePtr>&, bool); static SharedDbPtr openCatalog(SharedDbEnv&); @@ -84,6 +93,9 @@ public: const std::string& value() const; + const KeyCompareBasePtr& + getKeyCompare() const; + #ifdef __HP_aCC virtual int @@ -110,7 +122,8 @@ private: typedef std::map<MapKey, Freeze::SharedDb*> SharedDbMap; SharedDb(const MapKey&, const std::string&, const std::string&, - const ConnectionIPtr&, const std::vector<MapIndexBasePtr>&, bool); + const ConnectionIPtr&, const KeyCompareBasePtr&, + const std::vector<MapIndexBasePtr>&, bool); SharedDb(const MapKey&, DbEnv*); @@ -123,6 +136,7 @@ private: int _refCount; Ice::Int _trace; + KeyCompareBasePtr _keyCompare; IndexMap _indices; static SharedDbMap* sharedDbMap; @@ -146,6 +160,11 @@ SharedDb::value() const return _value; } +inline const Freeze::KeyCompareBasePtr& +SharedDb::getKeyCompare() const +{ + return _keyCompare; +} inline bool SharedDb::MapKey::operator<(const MapKey& rhs) const diff --git a/cpp/src/slice2freeze/Main.cpp b/cpp/src/slice2freeze/Main.cpp index 10d308cb595..6900e89d959 100644 --- a/cpp/src/slice2freeze/Main.cpp +++ b/cpp/src/slice2freeze/Main.cpp @@ -16,10 +16,14 @@ using namespace std; using namespace IceUtil; using namespace Slice; +static string ICE_ENCODING_COMPARE = "Freeze::IceEncodingCompare"; + struct DictIndex { string member; bool caseSensitive; + bool sort; + string userCompare; bool operator==(const DictIndex& rhs) const { @@ -32,6 +36,8 @@ struct Dict string name; string key; string value; + bool sort; + string userCompare; vector<DictIndex> indices; }; @@ -63,10 +69,15 @@ usage(const char* n) "-E Print preprocessor output on stdout.\n" "--include-dir DIR Use DIR as the header include directory in source files.\n" "--dll-export SYMBOL Use SYMBOL for DLL exports.\n" - "--dict NAME,KEY,VALUE Create a Freeze dictionary with the name NAME,\n" + "--dict NAME,KEY,VALUE[,sort[,COMPARE]]\n" + " Create a Freeze dictionary with the name NAME,\n" " using KEY as key, and VALUE as value. This\n" " option may be specified multiple times for\n" " different names. NAME may be a scoped name.\n" + " By default, keys are sorted using their binary\n" + " Ice-encoding representation. Use 'sort' to sort\n" + " with the COMPARE functor class. COMPARE's default\n" + " value is std::less<KEY>\n" "--index NAME,TYPE,MEMBER[,{case-sensitive|case-insensitive}]\n" " Create a Freeze evictor index with the name\n" " NAME for member MEMBER of class TYPE. This\n" @@ -74,7 +85,8 @@ usage(const char* n) " different names. NAME may be a scoped name.\n" " When member is a string, the case can be\n" " sensitive or insensitive (default is sensitive).\n" - "--dict-index DICT[,MEMBER][,{case-sensitive|case-insensitive}] \n" + "--dict-index DICT[,MEMBER][,{case-sensitive|case-insensitive}]\n" + " [,sort[,COMPARE]]\n" " Add an index to dictionary DICT. If MEMBER is \n" " specified, then DICT's VALUE must be a class or\n" " a struct, and MEMBER must designate a member of\n" @@ -82,6 +94,10 @@ usage(const char* n) " indexing. When the secondary key is a string, \n" " the case can be sensitive or insensitive (default\n" " is sensitive).\n" + " By default, keys are sorted using their binary\n" + " Ice-encoding representation. Use 'sort' to sort\n" + " with the COMPARE functor class. COMPARE's default\n" + " value is std::less<secondary key type>\n." "--output-dir DIR Create files in the directory DIR.\n" "-d, --debug Print debug messages.\n" "--ice Permit `Ice' prefix (for building Ice source code only)\n" @@ -117,7 +133,8 @@ printFreezeTypes(Output& out, const vector<Dict>& dicts, const vector<Index>& in out << "\n// Freeze types in this file:"; for(vector<Dict>::const_iterator p = dicts.begin(); p != dicts.end(); ++p) { - out << "\n// name=\"" << p->name << "\", key=\"" << p->key << "\", value=\"" << p->value << "\""; + out << "\n// name=\"" << p->name << "\", key=\"" + << p->key << "\", value=\"" << p->value << "\""; } for(vector<Index>::const_iterator q = indices.begin(); q != indices.end(); ++q) @@ -132,6 +149,27 @@ printFreezeTypes(Output& out, const vector<Dict>& dicts, const vector<Index>& in out << '\n'; } +template<class T> +inline string +getCompare(const T& t, const string& keyType) +{ + if(t.sort) + { + if(t.userCompare == "") + { + return "std::less<" + keyType + ">"; + } + else + { + return t.userCompare; + } + } + else + { + return ICE_ENCODING_COMPARE; + } +} + void writeCodecH(const TypePtr& type, const string& name, const string& freezeType, Output& H, const string& dllExport) { @@ -142,9 +180,9 @@ writeCodecH(const TypePtr& type, const string& name, const string& freezeType, O H << sp; H.inc(); H << nl << "static void write(" << inputTypeToString(type) - << ", Freeze::" << freezeType << "& bytes, const ::Ice::CommunicatorPtr& communicator);"; - H << nl << "static void read(" << typeToString(type) << "&, const Freeze::" << freezeType << "& bytes, " - << "const ::Ice::CommunicatorPtr& communicator);"; + << ", Freeze::" << freezeType << "&, const ::Ice::CommunicatorPtr&);"; + H << nl << "static void read(" << typeToString(type) << "&, const Freeze::" << freezeType << "&, " + << "const ::Ice::CommunicatorPtr&);"; H << nl << "static const std::string& typeId();"; H << eb << ';'; } @@ -231,11 +269,16 @@ writeDictWithIndicesH(const string& name, const Dict& dict, const TypePtr& keyType, const TypePtr& valueType, Output& H, const string& dllExport) { + string compare = getCompare(dict, typeToString(keyType)); - string templateParams = string("< ") + typeToString(keyType) + ", " + string templateParams = string("<") + typeToString(keyType) + ", " + typeToString(valueType) + ", " + name + "KeyCodec, " - + name + "ValueCodec>"; - + + name + "ValueCodec, " + compare + " >"; + + string keyCompareParams = + string("< ") + typeToString(keyType) + ", " + + name + "KeyCodec, " + compare + " >"; + vector<string> capitalizedMembers; size_t i; for(i = 0; i < dict.indices.size(); ++i) @@ -264,6 +307,7 @@ writeDictWithIndicesH(const string& name, const Dict& dict, // // Typedefs // + /* H << nl << "typedef std::pair<const " << typeToString(keyType) << ", const" << typeToString(valueType) << "> value_type;"; @@ -271,27 +315,44 @@ writeDictWithIndicesH(const string& name, const Dict& dict, H << nl << "typedef Freeze::ConstIterator" << templateParams << " const_iterator;"; H << nl << "typedef size_t size_type;"; H << nl << "typedef ptrdiff_t difference_type;"; - + */ + // // Nested index classes // for(i = 0; i < capitalizedMembers.size(); ++i) { - H << sp << nl << "class " << dllExport << capitalizedMembers[i] << "Index" - << " : public Freeze::MapIndexBase"; + string className = capitalizedMembers[i] + "Index"; + + string indexCompare = getCompare(dict.indices[i], typeToString(indexTypes[i])); + + string indexCompareParams = + string("< ") + typeToString(indexTypes[i]) + ", " + + className + ", " + indexCompare + " >"; + + H << sp << nl << "class " << dllExport << className + << " : public Freeze::MapIndex" << indexCompareParams; H << sb; H.dec(); H << sp << nl << "public:"; H << sp; H.inc(); - H << nl << capitalizedMembers[i] << "Index(const std::string&);"; + H << nl << capitalizedMembers[i] << "Index(const std::string&, const " + << indexCompare << "& = " << indexCompare << "());"; H << sp; - H << nl << "static void writeIndex(" << inputTypeToString(indexTypes[i]) + + // + // Codec + // + H << nl << "static void write(" << inputTypeToString(indexTypes[i]) << ", Freeze::Key&, const Ice::CommunicatorPtr&);"; + H << nl << "static void read(" + << typeToString(indexTypes[i]) + << "&, const Freeze::Key&, const ::Ice::CommunicatorPtr&);"; H.dec(); H << sp << nl << "protected:"; @@ -307,15 +368,20 @@ writeDictWithIndicesH(const string& name, const Dict& dict, // Constructors // H << sp; - H << nl << name << "(const Freeze::ConnectionPtr&, const std::string&, bool = true);"; + H << nl << name << "(const Freeze::ConnectionPtr&, const std::string&, " + << "bool = true, const " << compare << "& = " << compare << "());"; H << sp; H << nl << "template <class _InputIterator>" - << nl << name << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName, bool __createDb, " - << "_InputIterator __first, _InputIterator __last)"; + << nl << name << "(const Freeze::ConnectionPtr& __connection, " + << "const std::string& __dbName, bool __createDb, " + << "_InputIterator __first, _InputIterator __last, " + << "const " << compare << "& __compare = " << compare << "())"; H.inc(); H << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())"; H.dec(); H << sb; + H << nl << "Freeze::KeyCompareBasePtr __keyCompare = " + << "new Freeze::KeyCompare" << keyCompareParams << "(__compare, _communicator);"; H << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;"; for(i = 0; i < capitalizedMembers.size(); ++i) { @@ -330,7 +396,7 @@ writeDictWithIndicesH(const string& name, const Dict& dict, } H << nl << "this->_helper.reset(Freeze::MapHelper::create(__connection, __dbName, " << name + "KeyCodec::typeId(), " - << name + "ValueCodec::typeId(), __indices, __createDb));"; + << name + "ValueCodec::typeId(), __keyCompare, __indices, __createDb));"; H << nl << "while(__first != __last)"; H << sb; H << nl << "put(*__first);"; @@ -339,16 +405,32 @@ writeDictWithIndicesH(const string& name, const Dict& dict, H << eb; // - // Find and count functions + // Find, lowerBound, upperBound, equalRange and count functions // for(i = 0; i < capitalizedMembers.size(); ++i) { H << sp; H << nl << "iterator findBy" << capitalizedMembers[i] - << "(" << inputTypeToString(indexTypes[i]) << ");"; + << "(" << inputTypeToString(indexTypes[i]) << ", bool = true);"; H << nl << "const_iterator findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << ", bool = true) const;"; + + H << nl << "iterator lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << ");"; + H << nl << "const_iterator lowerBoundFor" << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i]) << ") const;"; + H << nl << "iterator upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << ");"; + H << nl << "const_iterator upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << ") const;"; + + H << nl << "std::pair<iterator, iterator> equalRangeFor" + << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i]) << ");"; + + H << nl << "std::pair<const_iterator, const_iterator> equalRangeFor" + << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i]) << ") const;"; + string countFunction = dict.indices[i].member.empty() ? "valueCount" : dict.indices[i].member + "Count"; @@ -364,10 +446,16 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di const vector<TypePtr> indexTypes, const TypePtr& keyType, const TypePtr& valueType, Output& C) -{ - string templateParams = string("< ") + typeToString(keyType) + ", " +{ + string compare = getCompare(dict, typeToString(keyType)); + + string templateParams = string("<") + typeToString(keyType) + ", " + typeToString(valueType) + ", " + name + "KeyCodec, " - + name + "ValueCodec>"; + + name + "ValueCodec, " + compare + " >"; + + string keyCompareParams = + string("< ") + typeToString(keyType) + ", " + + name + "KeyCodec, " + compare + " >"; vector<string> capitalizedMembers; size_t i; @@ -390,16 +478,24 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di // // Nested index classes // - for(i = 0; i < capitalizedMembers.size(); ++i) { string className = capitalizedMembers[i] + "Index"; + string indexCompare = + getCompare(dict.indices[i], typeToString(indexTypes[i])); + + string indexCompareParams = + string("< ") + typeToString(indexTypes[i]) + ", " + + className + ", " + indexCompare + " >"; + C << sp << nl << absolute << "::" << className << "::" << className - << "(const std::string& __name)"; + << "(const std::string& __name, " + << "const " << indexCompare << "& __compare)"; C.inc(); - C << nl << ": Freeze::MapIndexBase(__name)"; + C << nl << ": Freeze::MapIndex" + << indexCompareParams << "(__name, __compare)"; C.dec(); C << sb; C << eb; @@ -436,13 +532,13 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di param += "." + dict.indices[i].member; } } - C << nl << "writeIndex(" << param << ", __k, _communicator);"; + C << nl << "write(" << param << ", __k, _communicator);"; } C << eb; C << sp << nl << "void" << nl << absolute << "::" << className << "::" - << "writeIndex(" << inputTypeToString(indexTypes[i]) + << "write(" << inputTypeToString(indexTypes[i]) << " __index, Freeze::Key& __bytes, const Ice::CommunicatorPtr& __communicator)"; C << sb; @@ -452,6 +548,8 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di } else { + assert(!indexTypes[i]->usesClasses()); + C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(__communicator);"; C << nl << "IceInternal::BasicStream __stream(__instance.get());"; @@ -468,27 +566,46 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di } writeMarshalUnmarshalCode(C, indexTypes[i], valueS, true, "__stream", false); - if(indexTypes[i]->usesClasses()) - { - C << nl << "__stream.writePendingObjects();"; - } C << nl << "::std::vector<Ice::Byte>(__stream.b.begin(), __stream.b.end()).swap(__bytes);"; } C << eb; - } + C << sp << nl << "void" + << nl << absolute << "::" << className << "::" + << "read(" << typeToString(indexTypes[i]) + << "& __index, const Freeze::Key& __bytes, const Ice::CommunicatorPtr& __communicator)"; + C << sb; + + if(optimize) + { + C << nl << absolute << "ValueCodec::read(__index, __bytes, __communicator);"; + } + else + { + C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(__communicator);"; + C << nl << "IceInternal::BasicStream __stream(__instance.get());"; + + C << nl << "__stream.b.resize(__bytes.size());"; + C << nl << "::memcpy(&__stream.b[0], &__bytes[0], __bytes.size());"; + C << nl << "__stream.i = __stream.b.begin();"; + writeMarshalUnmarshalCode(C, indexTypes[i], "__index", false, "__stream", false); + } + C << eb; + } // // Constructor // - C << sp << nl << absolute << "::" << name - << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName , bool __createDb)"; + << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName ," + << "bool __createDb, const " << compare << "& __compare)"; C.inc(); C << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())"; C.dec(); C << sb; + C << nl << "Freeze::KeyCompareBasePtr __keyCompare = " + << "new Freeze::KeyCompare" << keyCompareParams << "(__compare, _communicator);"; C << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;"; for(i = 0; i < capitalizedMembers.size(); ++i) { @@ -503,7 +620,7 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di } C << nl << "_helper.reset(Freeze::MapHelper::create(__connection, __dbName, " << absolute + "KeyCodec::typeId(), " - << absolute + "ValueCodec::typeId(), __indices, __createDb));"; + << absolute + "ValueCodec::typeId(), __keyCompare, __indices, __createDb));"; C << eb; // @@ -522,22 +639,80 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di C << sp << nl << absolute << "::iterator" << nl << absolute << "::" << "findBy" << capitalizedMembers[i] - << "(" << inputTypeToString(indexTypes[i]) << " __index)"; + << "(" << inputTypeToString(indexTypes[i]) << " __index, bool __onlyDups)"; C << sb; C << nl << "Freeze::Key __bytes;"; - C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; C << nl << "return iterator(_helper->index(" << indexName - << ")->untypedFind(__bytes, false), _communicator);"; + << ")->untypedFind(__bytes, false, __onlyDups), _communicator);"; C << eb; C << sp << nl << absolute << "::const_iterator" << nl << absolute << "::" << "findBy" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index, bool __onlyDups) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return const_iterator(_helper->index(" << indexName + << ")->untypedFind(__bytes, true, __onlyDups), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "lowerBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index)"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return iterator(_helper->index(" << indexName + << ")->untypedLowerBound(__bytes, false), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "lowerBoundFor" << capitalizedMembers[i] << "(" << inputTypeToString(indexTypes[i]) << " __index) const"; C << sb; C << nl << "Freeze::Key __bytes;"; - C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; C << nl << "return const_iterator(_helper->index(" << indexName - << ")->untypedFind(__bytes, true), _communicator);"; + << ")->untypedLowerBound(__bytes, true), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::iterator" + << nl << absolute << "::" << "upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index)"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return iterator(_helper->index(" << indexName + << ")->untypedUpperBound(__bytes, false), _communicator);"; + C << eb; + + C << sp << nl << absolute << "::const_iterator" + << nl << absolute << "::" << "upperBoundFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index) const"; + C << sb; + C << nl << "Freeze::Key __bytes;"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; + C << nl << "return const_iterator(_helper->index(" << indexName + << ")->untypedUpperBound(__bytes, true), _communicator);"; + C << eb; + + C << sp << nl << "std::pair<" << absolute << "::iterator, " + << absolute << "::iterator>" + << nl << absolute << "::" << "equalRangeFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index)"; + C << sb; + C << nl << "return std::make_pair(lowerBoundFor" << capitalizedMembers[i] + << "(__index), upperBoundFor" << capitalizedMembers[i] << "(__index));"; + C << eb; + + C << sp << nl << "std::pair<" << absolute << "::const_iterator, " + << absolute << "::const_iterator>" + << nl << absolute << "::" << "equalRangeFor" << capitalizedMembers[i] + << "(" << inputTypeToString(indexTypes[i]) << " __index) const"; + C << sb; + C << nl << "return std::make_pair(lowerBoundFor" << capitalizedMembers[i] + << "(__index), upperBoundFor" << capitalizedMembers[i] << "(__index));"; C << eb; string countFunction = dict.indices[i].member.empty() ? "valueCount" @@ -548,7 +723,7 @@ writeDictWithIndicesC(const string& name, const string& absolute, const Dict& di << "(" << inputTypeToString(indexTypes[i]) << " __index) const"; C << sb; C << nl << "Freeze::Key __bytes;"; - C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);"; + C << nl << indexClassName << "::" << "write(__index, __bytes, _communicator);"; C << nl << "return _helper->index(" << indexName << ")->untypedCount(__bytes);"; C << eb; @@ -616,8 +791,12 @@ writeDict(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C, c if(dict.indices.size() == 0) { - H << sp << nl << "typedef Freeze::Map< " << typeToString(keyType) << ", " << typeToString(valueType) << ", " - << name << "KeyCodec, " << name << "ValueCodec> " << name << ";"; + string compare = getCompare(dict, typeToString(keyType)); + + H << sp << nl << "typedef Freeze::Map< " << typeToString(keyType) + << ", " << typeToString(valueType) << ", " + << name << "KeyCodec, " << name << "ValueCodec, " << compare + << " > " << name << ";"; } else { @@ -691,7 +870,8 @@ writeDict(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C, c if(dataMember == 0) { - cerr << n << ": The value of `" << dict.name << "' has no data member named `" << index.member << "'" << endl; + cerr << n << ": The value of `" << dict.name + << "' has no data member named `" << index.member << "'" << endl; return false; } @@ -956,9 +1136,6 @@ writeIndex(const string& n, UnitPtr& u, const Index& index, Output& H, Output& C return true; } - - - int main(int argc, char* argv[]) { @@ -1080,7 +1257,44 @@ main(int argc, char* argv[]) dict.key = s.substr(0, pos); s.erase(0, pos + 1); } - dict.value = s; + pos = s.find(','); + if(pos == string::npos) + { + dict.value = s; + dict.sort = false; + } + else + { + dict.value = s.substr(0, pos); + s.erase(0, pos + 1); + + pos = s.find(','); + if(pos == string::npos) + { + if(s != "sort") + { + cerr << argv[0] << ": " << *i + << ": nothing or ',sort' expected after value-type" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + dict.sort = true; + } + else + { + string sort = s.substr(0, pos); + s.erase(0, pos + 1); + if(sort != "sort") + { + cerr << argv[0] << ": " << *i + << ": nothing or ',sort' expected after value-type" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + dict.sort = true; + dict.userCompare = s; + } + } if(dict.name.empty()) { @@ -1185,39 +1399,96 @@ main(int argc, char* argv[]) string dictName; DictIndex index; - string::size_type pos; - - string caseString = "case-sensitive"; - pos = s.find(','); - if(pos != string::npos) + index.sort = false; + index.caseSensitive = true; + + string::size_type pos = s.find(','); + if(pos == string::npos) + { + dictName = s; + } + else { dictName = s.substr(0, pos); s.erase(0, pos + 1); - pos = s.find(','); - if(pos != string::npos) + bool done = false; + while(!done) { - index.member = s.substr(0, pos); - s.erase(0, pos + 1); - caseString = s; - } - else - { - if(s == "case-sensitive" || s == "case-insensitive") + pos = s.find(','); + if(pos == string::npos) { - caseString = s; + if(s == "sort") + { + index.sort = true; + } + else if(s == "case-sensitive") + { + index.caseSensitive = true; + } + else if(s == "case-insensitive") + { + index.caseSensitive = false; + } + else if(index.member.empty()) + { + if(s == "\\sort") + { + index.member = "sort"; + } + else + { + index.member = s; + } + } + else + { + cerr << argv[0] << ": " << *i << ": syntax error" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } + done = true; } else { - index.member = s; + string subs = s.substr(0, pos); + s.erase(0, pos + 1); + + if(subs == "sort") + { + index.sort = true; + index.userCompare = s; + done = true; + } + else if(subs == "case-sensitive") + { + index.caseSensitive = true; + } + else if(subs == "case-insensitive") + { + index.caseSensitive = false; + } + else if(index.member.empty()) + { + if(subs == "\\sort") + { + index.member = "sort"; + } + else + { + index.member = subs; + } + } + else + { + cerr << argv[0] << ": " << *i << ": syntax error" << endl; + usage(argv[0]); + return EXIT_FAILURE; + } } } } - else - { - dictName = s; - } - + if(dictName.empty()) { cerr << argv[0] << ": " << *i << ": no dictionary specified" << endl; @@ -1225,14 +1496,6 @@ main(int argc, char* argv[]) return EXIT_FAILURE; } - if(caseString != "case-sensitive" && caseString != "case-insensitive") - { - cerr << argv[0] << ": " << *i << ": the case can be `case-sensitive' or `case-insensitive'" << endl; - usage(argv[0]); - return EXIT_FAILURE; - } - index.caseSensitive = (caseString == "case-sensitive"); - bool found = false; for(vector<Dict>::iterator p = dicts.begin(); p != dicts.end(); ++p) { @@ -1240,7 +1503,8 @@ main(int argc, char* argv[]) { if(find(p->indices.begin(), p->indices.end(), index) != p->indices.end()) { - cerr << argv[0] << ": --dict-index " << *i << ": this dict-index is defined twice" << endl; + cerr << argv[0] << ": --dict-index " << *i + << ": this dict-index is defined twice" << endl; return EXIT_FAILURE; } p->indices.push_back(index); diff --git a/cpp/test/Freeze/dbmap/Client.cpp b/cpp/test/Freeze/dbmap/Client.cpp index d2235fb5870..1dad4cca175 100644 --- a/cpp/test/Freeze/dbmap/Client.cpp +++ b/cpp/test/Freeze/dbmap/Client.cpp @@ -13,6 +13,7 @@ #include <ByteIntMap.h> #include <IntIdentityMap.h> #include <IntIdentityMapWithIndex.h> +#include <SortedMap.h> #include <Freeze/TransactionHolder.h> #include <algorithm> @@ -199,8 +200,9 @@ private: int -run(const CommunicatorPtr& communicator, const string& envName, const string& dbName) +run(const CommunicatorPtr& communicator, const string& envName) { + const string dbName = "binary"; Freeze::ConnectionPtr connection = createConnection(communicator, envName); ByteIntMap m(connection, dbName); @@ -617,6 +619,110 @@ run(const CommunicatorPtr& communicator, const string& envName, const string& db } iim.clear(); } + cout << "ok" << endl; + + cout << "testing sorting... " << flush; + { + SortedMap sm(connection, "sortedIntIdentity"); + + TransactionHolder txHolder(connection); + for(int i = 0; i < 1000; i++) + { + int k = rand() % 1000; + + Ice::Identity id; + id.name = "foo"; + id.category = 'a' + static_cast<char>(k % 26); + + sm.put(SortedMap::value_type(k, id)); + } + txHolder.commit(); + } + + { + SortedMap sm(connection, "sortedIntIdentity"); + { + for(int i = 0; i < 100; ++i) + { + int k = rand() % 1000; + SortedMap::iterator p = sm.lower_bound(k); + if(p != sm.end()) + { + test(p->first >= k); + SortedMap::iterator q = sm.upper_bound(k); + if(q == sm.end()) + { + test(p->first == k); + } + else + { + test((p->first == k && q->first > k) || + (p->first > k && q->first == p->first)); + } + } + } + } + + { + for(int i = 0; i < 100; ++i) + { + string category; + category = static_cast<char>('a' + rand() % 26); + + SortedMap::iterator p = sm.findByCategory(category); + if(p != sm.end()) + { + SortedMap::iterator q = sm.lowerBoundForCategory(category); + test(p == q); + do + { + q++; + } while(q != sm.end() && q->second.category == category); + + if(q != sm.end()) + { + test(q == sm.upperBoundForCategory(category)); + } + } + else + { + SortedMap::iterator q = sm.lowerBoundForCategory(category); + if(q != sm.end()) + { + test(p != q); + test(q->second.category < category); + category = q->second.category; + + do + { + q++; + } while(q != sm.end() && q->second.category == category); + + if(q != sm.end()) + { + test(q == sm.upperBoundForCategory(category)); + } + } + } + } + } + + { + string category = "z"; + SortedMap::iterator p = sm.lowerBoundForCategory(category); + + while(p != sm.end()) + { + test(p->second.category <= category); + category = p->second.category; + // cerr << category << ":" << p->first << endl; + ++p; + } + } + + sm.clear(); + } + cout << "ok" << endl; @@ -641,7 +747,7 @@ main(int argc, char* argv[]) envName += "db"; } - status = run(communicator, envName, "binary"); + status = run(communicator, envName); } catch(const Ice::Exception& ex) { diff --git a/cpp/test/Freeze/dbmap/Makefile b/cpp/test/Freeze/dbmap/Makefile index 8d79e39b1e4..ebe39a3e43a 100644 --- a/cpp/test/Freeze/dbmap/Makefile +++ b/cpp/test/Freeze/dbmap/Makefile @@ -16,7 +16,8 @@ TARGETS = $(CLIENT) OBJS = Client.o \ ByteIntMap.o \ IntIdentityMap.o \ - IntIdentityMapWithIndex.o + IntIdentityMapWithIndex.o \ + SortedMap.o SRCS = $(OBJS:.o=.cpp) @@ -40,9 +41,12 @@ IntIdentityMapWithIndex.h IntIdentityMapWithIndex.cpp: $(SLICE2FREEZE) rm -f IntIdentityMapWithIndex.h IntIdentityMapWithIndex.cpp $(SLICE2FREEZE) --ice $(SLICE2CPPFLAGS) --dict Test::IntIdentityMapWithIndex,int,Ice::Identity --dict-index Test::IntIdentityMapWithIndex,category IntIdentityMapWithIndex $(slicedir)/Ice/Identity.ice +SortedMap.h SortedMap.cpp: $(SLICE2FREEZE) + rm -f SortedMap.h SortedMap.cpp + $(SLICE2FREEZE) --ice $(SLICE2CPPFLAGS) --dict Test::SortedMap,int,Ice::Identity,sort SortedMap --dict-index "Test::SortedMap,category,sort,std::greater<std::string>" $(slicedir)/Ice/Identity.ice clean:: - rm -f ByteIntMap.h ByteIntMap.cpp IntIdentityMap.h IntIdentityMap.cpp IntIdentityMapWithIndex.h IntIdentityMapWithIndex.cpp + rm -f ByteIntMap.h ByteIntMap.cpp IntIdentityMap.h IntIdentityMap.cpp IntIdentityMapWithIndex.h IntIdentityMapWithIndex.cpp SortedMap.h SortedMap.cpp clean:: rm -f db/binary db/binary.* db/intIdentity db/intIdentity.* db/__catalog db/log.* diff --git a/cpp/test/Freeze/dbmap/dbmap.dsp b/cpp/test/Freeze/dbmap/dbmap.dsp index b619a4f9656..1b19776f9d4 100644 --- a/cpp/test/Freeze/dbmap/dbmap.dsp +++ b/cpp/test/Freeze/dbmap/dbmap.dsp @@ -25,7 +25,7 @@ CFG=dbmap - Win32 Debug # PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
-CPP=cl.exe
+CPP=xicl6.exe
RSC=rc.exe
!IF "$(CFG)" == "dbmap - Win32 Release"
@@ -49,7 +49,7 @@ RSC=rc.exe BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-LINK32=link.exe
+LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
# ADD LINK32 /nologo /subsystem:console /incremental:yes /machine:I386 /out:"client.exe" /libpath:"../../../lib" /FIXED:no
# SUBTRACT LINK32 /debug /nodefaultlib
@@ -75,7 +75,7 @@ LINK32=link.exe BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
-LINK32=link.exe
+LINK32=xilink6.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
# ADD LINK32 /nologo /subsystem:console /debug /machine:I386 /out:"client.exe" /pdbtype:sept /libpath:"../../../lib" /FIXED:no
# SUBTRACT LINK32 /pdb:none
@@ -105,6 +105,10 @@ SOURCE=.\IntIdentityMap.cpp SOURCE=.\IntIdentityMapWithIndex.cpp
# End Source File
+# Begin Source File
+
+SOURCE=.\SortedMap.cpp
+# End Source File
# End Group
# Begin Group "Header Files"
@@ -139,6 +143,7 @@ BuildCmds= \ ..\..\..\bin\slice2freeze.exe --dict Test::ByteIntMap,byte,int --dict-index Test::ByteIntMap ByteIntMap \
..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::IntIdentityMap,int,Ice::Identity IntIdentityMap ../../../slice/Ice/Identity.ice \
..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::IntIdentityMapWithIndex,int,Ice::Identity IntIdentityMapWithIndex --dict-index Test::IntIdentityMapWithIndex,category ../../../slice/Ice/Identity.ice \
+ ..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::SortedMap,int,Ice::Identity,sort SortedMap --dict-index "Test::SortedMap,category,sort,std::greater<std::string>" ../../../slice/Ice/Identity.ice \
"ByteIntMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
@@ -158,6 +163,12 @@ BuildCmds= \ "IntIdentityMapWithIndex.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
+
+"SortedMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"SortedMap.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
# End Custom Build
!ELSEIF "$(CFG)" == "dbmap - Win32 Debug"
@@ -170,6 +181,7 @@ BuildCmds= \ ..\..\..\bin\slice2freeze.exe --dict Test::ByteIntMap,byte,int --dict-index Test::ByteIntMap ByteIntMap \
..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::IntIdentityMap,int,Ice::Identity IntIdentityMap ../../../slice/Ice/Identity.ice \
..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::IntIdentityMapWithIndex,int,Ice::Identity IntIdentityMapWithIndex --dict-index Test::IntIdentityMapWithIndex,category ../../../slice/Ice/Identity.ice \
+ ..\..\..\bin\slice2freeze.exe --ice -I../../../slice --dict Test::SortedMap,int,Ice::Identity,sort SortedMap --dict-index "Test::SortedMap,category,sort,std::greater<std::string>" ../../../slice/Ice/Identity.ice \
"ByteIntMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
@@ -189,6 +201,12 @@ BuildCmds= \ "IntIdentityMapWithIndex.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)
+
+"SortedMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
+
+"SortedMap.cpp" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ $(BuildCmds)
# End Custom Build
!ENDIF
|