summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBernard Normier <bernard@zeroc.com>2004-09-28 01:11:48 +0000
committerBernard Normier <bernard@zeroc.com>2004-09-28 01:11:48 +0000
commit705a304b097d8ed0b58cf147264449203355ec51 (patch)
tree6dad2cde3699d64cc891ce60e84507e18f30a768
parentmake Application abstract (diff)
downloadice-705a304b097d8ed0b58cf147264449203355ec51.tar.bz2
ice-705a304b097d8ed0b58cf147264449203355ec51.tar.xz
ice-705a304b097d8ed0b58cf147264449203355ec51.zip
Index support for Freeze dictionaries
-rw-r--r--cpp/CHANGES6
-rw-r--r--cpp/demo/Freeze/bench/Client.cpp210
-rw-r--r--cpp/demo/Freeze/bench/Makefile13
-rw-r--r--cpp/demo/Freeze/bench/Test.ice1
-rw-r--r--cpp/demo/Freeze/bench/bench.dsp20
-rw-r--r--cpp/include/Freeze/Map.h202
-rw-r--r--cpp/src/Freeze/IndexI.cpp7
-rw-r--r--cpp/src/Freeze/MapI.cpp352
-rw-r--r--cpp/src/Freeze/MapI.h32
-rw-r--r--cpp/src/Freeze/SharedDb.cpp154
-rw-r--r--cpp/src/Freeze/SharedDb.h47
-rw-r--r--cpp/src/slice2freeze/Main.cpp544
-rw-r--r--cpp/test/Freeze/dbmap/Client.cpp54
-rw-r--r--cpp/test/Freeze/dbmap/Makefile2
-rw-r--r--cpp/test/Freeze/dbmap/dbmap.dsp6
15 files changed, 1509 insertions, 141 deletions
diff --git a/cpp/CHANGES b/cpp/CHANGES
index 89893c283f9..0b1adf5eea0 100644
--- a/cpp/CHANGES
+++ b/cpp/CHANGES
@@ -1,6 +1,12 @@
Changes since version 1.5.1
---------------------------
+- Freeze dictionaries now support indices. You can index on the
+ full value of the dictionary, or on a member (when the value
+ is a struct or a class). When you index on a member, you
+ can define several indices (for different members).
+ See the Freeze bench demo and the Freeze dbmap test for examples.
+
- The Ice::Service class no longer resets the umask to 0, but rather
uses the inherited umask.
diff --git a/cpp/demo/Freeze/bench/Client.cpp b/cpp/demo/Freeze/bench/Client.cpp
index af020982a90..70b38d080b2 100644
--- a/cpp/demo/Freeze/bench/Client.cpp
+++ b/cpp/demo/Freeze/bench/Client.cpp
@@ -149,12 +149,33 @@ public:
private:
- void IntIntMapTest();
- void generatedRead(IntIntMap&, int, const GeneratorPtr&);
- void Struct1Struct2MapTest();
- void Struct1Class1MapTest();
+ template<class T> void IntIntMapTest(const string&, T* = 0);
+ void IntIntMapIndexTest(IntIntMap&)
+ {}
+ void IntIntMapIndexTest(IndexedIntIntMap&);
+
+ template<class T> void generatedRead(T&, int, const GeneratorPtr&);
+ void generatedReadWithIndex(IntIntMap&, int, const GeneratorPtr&)
+ {}
+ void generatedReadWithIndex(IndexedIntIntMap&, int, const GeneratorPtr&);
+
+ template<class T> void Struct1Struct2MapTest(const string&, T* = 0);
+ void Struct1Struct2MapIndexTest(Struct1Struct2Map&)
+ {}
+ void Struct1Struct2MapIndexTest(IndexedStruct1Struct2Map&);
+
+ template<class T> void Struct1Class1MapTest(const string&, T* = 0);
+ void Struct1Class1MapIndexTest(Struct1Class1Map&)
+ {}
+ void Struct1Class1MapIndexTest(IndexedStruct1Class1Map&);
+
+ template<class T> void IntIntMapReadTest(const string&, T* = 0);
+ void IntIntMapReadIndexTest(IntIntMap&)
+ {}
+ void IntIntMapReadIndexTest(IndexedIntIntMap&);
+
+
void Struct1ObjectMapTest();
- void IntIntMapReadTest();
const string _envName;
Freeze::ConnectionPtr _connection;
@@ -168,10 +189,11 @@ TestApp::TestApp(const string& envName) :
{
}
+template<class T>
void
-TestApp::IntIntMapTest()
+TestApp::IntIntMapTest(const string& mapName, T*)
{
- IntIntMap m(_connection, "IntIntMap");
+ T m(_connection, mapName);
//
// Populate the database.
@@ -182,7 +204,7 @@ TestApp::IntIntMapTest()
TransactionHolder txHolder(_connection);
for(i = 0; i < _repetitions; ++i)
{
- m.put(IntIntMap::value_type(i, i));
+ m.put(typename T::value_type(i, i));
}
txHolder.commit();
}
@@ -198,7 +220,7 @@ TestApp::IntIntMapTest()
_watch.start();
for(i = 0; i < _repetitions; ++i)
{
- IntIntMap::iterator p = m.find(i);
+ typename T::iterator p = m.find(i);
test(p != m.end());
test(p->second == i);
}
@@ -209,6 +231,11 @@ TestApp::IntIntMapTest()
cout << "\ttime per read: " << perRecord << "ms" << endl;
//
+ // Optional index sub-test
+ //
+ IntIntMapIndexTest(m);
+
+ //
// Remove each record.
//
_watch.start();
@@ -228,13 +255,34 @@ TestApp::IntIntMapTest()
}
void
-TestApp::generatedRead(IntIntMap& m, int reads , const GeneratorPtr& gen)
+TestApp::IntIntMapIndexTest(IndexedIntIntMap& m)
+{
+ //
+ // Read each record.
+ //
+ _watch.start();
+ for(int i = 0; i < _repetitions; ++i)
+ {
+ IndexedIntIntMap::iterator p = m.findByValue(i);
+ test(p != m.end());
+ test(p->second == i);
+ }
+ double total = _watch.stop();
+ double perRecord = total / _repetitions;
+
+ cout << "\ttime for " << _repetitions << " reverse (indexed) reads: " << total << "ms" << endl;
+ cout << "\ttime per reverse read: " << perRecord << "ms" << endl;
+}
+
+template<class T>
+void
+TestApp::generatedRead(T& m, int reads , const GeneratorPtr& gen)
{
_watch.start();
for(int i = 0; i < reads; ++i)
{
int key = gen->next();
- IntIntMap::iterator p = m.find(key);
+ typename T::iterator p = m.find(key);
test(p != m.end());
test(p->second == key);
}
@@ -244,12 +292,32 @@ TestApp::generatedRead(IntIntMap& m, int reads , const GeneratorPtr& gen)
cout << "\ttime for " << reads << " reads of " << gen->toString() << " records: " << total << "ms" << endl;
cout << "\ttime per read: " << perRecord << "ms" << endl;
+ generatedReadWithIndex(m, reads, gen);
}
void
-TestApp::IntIntMapReadTest()
+TestApp::generatedReadWithIndex(IndexedIntIntMap& m, int reads, const GeneratorPtr& gen)
{
- IntIntMap m(_connection, "IntIntMap");
+ _watch.start();
+ for(int i = 0; i < reads; ++i)
+ {
+ int value = gen->next();
+ IndexedIntIntMap::iterator p = m.findByValue(value);
+ test(p != m.end());
+ test(p->second == value);
+ }
+ double total = _watch.stop();
+ double perRecord = total / reads;
+
+ cout << "\ttime for " << reads << " reverse (indexed) reads of " << gen->toString() << " records: " << total << "ms" << endl;
+ cout << "\ttime per reverse read: " << perRecord << "ms" << endl;
+}
+
+template<class T>
+void
+TestApp::IntIntMapReadTest(const string& mapName, T*)
+{
+ T m(_connection, mapName);
//
// Populate the database.
@@ -260,7 +328,7 @@ TestApp::IntIntMapReadTest()
TransactionHolder txHolder(_connection);
for(i = 0; i < _repetitions; ++i)
{
- m.put(IntIntMap::value_type(i, i));
+ m.put(typename T::value_type(i, i));
}
txHolder.commit();
}
@@ -304,10 +372,11 @@ TestApp::IntIntMapReadTest()
}
+template<class T>
void
-TestApp::Struct1Struct2MapTest()
+TestApp::Struct1Struct2MapTest(const string& mapName, T*)
{
- Struct1Struct2Map m(_connection, "Struct1Struct2");
+ T m(_connection, mapName);
//
// Populate the database.
@@ -324,7 +393,8 @@ TestApp::Struct1Struct2MapTest()
ostringstream os;
os << i;
s2.s = os.str();
- m.put(Struct1Struct2Map::value_type(s1, s2));
+ s2.s1 = s1;
+ m.put(typename T::value_type(s1, s2));
}
txHolder.commit();
}
@@ -341,7 +411,7 @@ TestApp::Struct1Struct2MapTest()
for(i = 0; i < _repetitions; ++i)
{
s1.l = i;
- Struct1Struct2Map::iterator p = m.find(s1);
+ typename T::iterator p = m.find(s1);
test(p != m.end());
ostringstream os;
os << i;
@@ -354,6 +424,11 @@ TestApp::Struct1Struct2MapTest()
cout << "\ttime per read: " << perRecord << "ms" << endl;
//
+ // Optional index test
+ //
+ Struct1Struct2MapIndexTest(m);
+
+ //
// Remove each record.
//
_watch.start();
@@ -372,10 +447,46 @@ TestApp::Struct1Struct2MapTest()
cout << "\ttime for " << _repetitions << " removes: " << total << "ms" << endl;
cout << "\ttime per remove: " << perRecord << "ms" << endl;
}
+
void
-TestApp::Struct1Class1MapTest()
+TestApp::Struct1Struct2MapIndexTest(IndexedStruct1Struct2Map& m)
{
- Struct1Class1Map m(_connection, "Struct1Class1");
+ int i;
+ _watch.start();
+ for(i = 0; i < _repetitions; ++i)
+ {
+ ostringstream os;
+ os << i;
+
+ IndexedStruct1Struct2Map::iterator p = m.findByS(os.str());
+ test(p != m.end());
+ test(p->first.l == i);
+ test(p->second.s1.l == i);
+ }
+
+ for(i = 0; i < _repetitions; ++i)
+ {
+ Struct1 s1;
+ s1.l = i;
+ IndexedStruct1Struct2Map::iterator p = m.findByS1(s1);
+ test(p != m.end());
+ test(p->first.l == i);
+ test(p->second.s1.l == i);
+ }
+
+ double total = _watch.stop();
+ double perRecord = total / (2 *_repetitions);
+
+ cout << "\ttime for " << 2 *_repetitions << " indexed reads: " << total << "ms" << endl;
+ cout << "\ttime per indexed read: " << perRecord << "ms" << endl;
+}
+
+
+template<class T>
+void
+TestApp::Struct1Class1MapTest(const string& mapName, T*)
+{
+ T m(_connection, mapName);
//
// Populate the database.
@@ -392,7 +503,7 @@ TestApp::Struct1Class1MapTest()
ostringstream os;
os << i;
c1->s = os.str();
- m.put(Struct1Class1Map::value_type(s1, c1));
+ m.put(typename T::value_type(s1, c1));
}
txHolder.commit();
}
@@ -409,7 +520,7 @@ TestApp::Struct1Class1MapTest()
for(i = 0; i < _repetitions; ++i)
{
s1.l = i;
- Struct1Class1Map::iterator p = m.find(s1);
+ typename T::iterator p = m.find(s1);
test(p != m.end());
ostringstream os;
os << i;
@@ -422,6 +533,12 @@ TestApp::Struct1Class1MapTest()
cout << "\ttime per read: " << perRecord << "ms" << endl;
//
+ // Optional index test
+ //
+
+ Struct1Class1MapIndexTest(m);
+
+ //
// Remove each record.
//
_watch.start();
@@ -441,6 +558,31 @@ TestApp::Struct1Class1MapTest()
cout << "\ttime per remove: " << perRecord << "ms" << endl;
}
+
+void
+TestApp::Struct1Class1MapIndexTest(IndexedStruct1Class1Map& m)
+{
+ //
+ // Read each record.
+ //
+ _watch.start();
+ for(int i = 0; i < _repetitions; ++i)
+ {
+ ostringstream os;
+ os << i;
+
+ IndexedStruct1Class1Map::iterator p = m.findByS(os.str());
+ test(p != m.end());
+ test(p->first.l == i);
+ }
+ double total = _watch.stop();
+ double perRecord = total / _repetitions;
+
+ cout << "\ttime for " << _repetitions << " indexed reads: " << total << "ms" << endl;
+ cout << "\ttime per indexed read: " << perRecord << "ms" << endl;
+}
+
+
void
TestApp::Struct1ObjectMapTest()
{
@@ -574,14 +716,23 @@ TestApp::run(int argc, char* argv[])
{
_connection = createConnection(communicator(), _envName);
- cout <<"IntIntMap" << endl;
- IntIntMapTest();
-
+ cout << "IntIntMap" << endl;
+ IntIntMapTest<IntIntMap>("IntIntMap");
+
+ cout << "IntIntMap with index" << endl;
+ IntIntMapTest<IndexedIntIntMap>("IndexedIntIntMap");
+
cout <<"Struct1Struct2Map" << endl;
- Struct1Struct2MapTest();
+ Struct1Struct2MapTest<Struct1Struct2Map>("Struct1Struct2Map");
+
+ cout <<"Struct1Struct2Map with index" << endl;
+ Struct1Struct2MapTest<IndexedStruct1Struct2Map>("IndexedStruct1Struct2Map");
cout <<"Struct1Class1Map" << endl;
- Struct1Class1MapTest();
+ Struct1Class1MapTest<Struct1Class1Map>("Struct1Class1Map");
+
+ cout <<"Struct1Class1Map with index" << endl;
+ Struct1Class1MapTest<IndexedStruct1Class1Map>("IndexedStruct1Class1Map");
MyFactoryPtr factory = new MyFactory();
factory->install(communicator());
@@ -590,7 +741,10 @@ TestApp::run(int argc, char* argv[])
Struct1ObjectMapTest();
cout <<"IntIntMap (read test)" << endl;
- IntIntMapReadTest();
+ IntIntMapReadTest<IntIntMap>("IntIntMap");
+
+ cout <<"IntIntMap (read test) (with index)" << endl;
+ IntIntMapReadTest<IndexedIntIntMap>("IndexedIntIntMap");
_connection->close();
diff --git a/cpp/demo/Freeze/bench/Makefile b/cpp/demo/Freeze/bench/Makefile
index 9233f920a74..fb0c07cf73f 100644
--- a/cpp/demo/Freeze/bench/Makefile
+++ b/cpp/demo/Freeze/bench/Makefile
@@ -29,9 +29,16 @@ $(CLIENT): $(OBJS) $(COBJS)
BenchTypes.h BenchTypes.cpp: Test.ice $(SLICE2FREEZE)
rm -f BenchTypes.h BenchTypes.cpp
- $(SLICE2FREEZE) -I$(slicedir) --dict IntIntMap,int,int --dict Struct1Struct2Map,Demo::Struct1,Demo::Struct2 \
- --dict Struct1Class1Map,Demo::Struct1,Demo::Class1 \
- --dict Struct1ObjectMap,Demo::Struct1,Object BenchTypes Test.ice
+ $(SLICE2FREEZE) -I$(slicedir) --dict Demo::IntIntMap,int,int --dict Demo::Struct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict Demo::Struct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict Demo::Struct1ObjectMap,Demo::Struct1,Object \
+ --dict Demo::IndexedIntIntMap,int,int --dict-index Demo::IndexedIntIntMap \
+ --dict Demo::IndexedStruct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict-index Demo::IndexedStruct1Struct2Map,s,case-insensitive \
+ --dict-index Demo::IndexedStruct1Struct2Map,s1 \
+ --dict Demo::IndexedStruct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict-index Demo::IndexedStruct1Class1Map,s,case-sensitive \
+ BenchTypes Test.ice
clean::
rm -f BenchTypes.h BenchTypes.cpp
diff --git a/cpp/demo/Freeze/bench/Test.ice b/cpp/demo/Freeze/bench/Test.ice
index 23d76da8ab1..25f92b5eaf3 100644
--- a/cpp/demo/Freeze/bench/Test.ice
+++ b/cpp/demo/Freeze/bench/Test.ice
@@ -18,6 +18,7 @@ struct Struct1
struct Struct2
{
string s;
+ Struct1 s1;
};
class Class1
diff --git a/cpp/demo/Freeze/bench/bench.dsp b/cpp/demo/Freeze/bench/bench.dsp
index 6d0e0ce5628..893c0806900 100644
--- a/cpp/demo/Freeze/bench/bench.dsp
+++ b/cpp/demo/Freeze/bench/bench.dsp
@@ -129,7 +129,15 @@ InputPath=.\Test.ice
BuildCmds= \
..\..\..\bin\slice2cpp.exe Test.ice \
- ..\..\..\bin\slice2freeze.exe --dict IntIntMap,int,int --dict Struct1Struct2Map,Demo::Struct1,Demo::Struct2 --dict Struct1Class1Map,Demo::Struct1,Demo::Class1 --dict Struct1ObjectMap,Demo::Struct1,Demo::Object BenchTypes Test.ice \
+ ..\..\..\bin\slice2freeze.exe --dict Demo::IntIntMap,int,int --dict Demo::Struct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict Demo::Struct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict Demo::Struct1ObjectMap,Demo::Struct1,Object \
+ --dict Demo::IndexedIntIntMap,int,int --dict-index Demo::IndexedIntIntMap \
+ --dict Demo::IndexedStruct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict-index Demo::IndexedStruct1Struct2Map,s,case-insensitive \
+ --dict-index Demo::IndexedStruct1Struct2Map,s1 \
+ --dict Demo::IndexedStruct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict-index Demo::IndexedStruct1Class1Map,s,case-sensitive BenchTypes Test.ice \
"Test.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
@@ -153,7 +161,15 @@ InputPath=.\Test.ice
BuildCmds= \
..\..\..\bin\slice2cpp.exe Test.ice \
- ..\..\..\bin\slice2freeze.exe --dict IntIntMap,int,int --dict Struct1Struct2Map,Demo::Struct1,Demo::Struct2 --dict Struct1Class1Map,Demo::Struct1,Demo::Class1 --dict Struct1ObjectMap,Demo::Struct1,Object BenchTypes Test.ice \
+ ..\..\..\bin\slice2freeze.exe --dict Demo::IntIntMap,int,int --dict Demo::Struct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict Demo::Struct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict Demo::Struct1ObjectMap,Demo::Struct1,Object \
+ --dict Demo::IndexedIntIntMap,int,int --dict-index Demo::IndexedIntIntMap \
+ --dict Demo::IndexedStruct1Struct2Map,Demo::Struct1,Demo::Struct2 \
+ --dict-index Demo::IndexedStruct1Struct2Map,s,case-insensitive \
+ --dict-index Demo::IndexedStruct1Struct2Map,s1 \
+ --dict Demo::IndexedStruct1Class1Map,Demo::Struct1,Demo::Class1 \
+ --dict-index Demo::IndexedStruct1Class1Map,s,case-sensitive BenchTypes Test.ice \
"Test.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
diff --git a/cpp/include/Freeze/Map.h b/cpp/include/Freeze/Map.h
index e4b06220647..1429b4fb46c 100644
--- a/cpp/include/Freeze/Map.h
+++ b/cpp/include/Freeze/Map.h
@@ -25,6 +25,49 @@ namespace Freeze
{
class IteratorHelper;
+class MapHelper;
+
+
+class MapIndexI;
+class MapHelperI;
+class IteratorHelperI;
+class SharedDb;
+
+class FREEZE_API MapIndexBase : public IceUtil::Shared
+{
+public:
+
+ virtual ~MapIndexBase();
+
+ const std::string& name() const;
+
+ IteratorHelper* untypedFind(const Key&, bool) const;
+ int untypedCount(const Key&) const;
+
+ //
+ // Implemented by the generated code
+ //
+ virtual void marshalKey(const Value&, Key&) const = 0;
+
+protected:
+
+ MapIndexBase(const std::string&);
+
+ Ice::CommunicatorPtr _communicator;
+
+private:
+
+ friend class MapHelperI;
+ friend class IteratorHelperI;
+ friend class SharedDb;
+
+ std::string _name;
+ MapIndexI* _impl;
+ const MapHelperI* _map;
+};
+
+typedef IceUtil::Handle<MapIndexBase> MapIndexBasePtr;
+
class FREEZE_API MapHelper
{
@@ -33,6 +76,7 @@ public:
static MapHelper*
create(const Freeze::ConnectionPtr& connection,
const std::string& dbName,
+ const std::vector<MapIndexBasePtr>&,
bool createDb);
virtual ~MapHelper() = 0;
@@ -61,6 +105,8 @@ public:
virtual void
closeAllIterators() = 0;
+ virtual const MapIndexBasePtr&
+ index(const std::string&) const = 0;
};
@@ -77,6 +123,9 @@ public:
virtual IteratorHelper*
clone() const = 0;
+ virtual const Key*
+ get() const = 0;
+
virtual void
get(const Key*&, const Value*&) const = 0;
@@ -88,13 +137,9 @@ public:
virtual bool
next() const = 0;
-
- virtual bool
- equals(const IteratorHelper&) const = 0;
};
-
//
// Forward declaration
//
@@ -189,14 +234,22 @@ public:
bool operator==(const Iterator& rhs) const
{
- if(_helper.get() != 0 && rhs._helper.get() != 0)
+ if(_helper.get() == rhs._helper.get())
{
- return _helper->equals(*rhs._helper.get());
+ return true;
}
- else
+
+ if(_helper.get() != 0 && rhs._helper.get() != 0)
{
- return _helper.get() == rhs._helper.get();
+ const Key* lhsKey = _helper->get();
+ const Key* rhsKey = rhs._helper->get();
+
+ if(lhsKey != 0 && rhsKey != 0)
+ {
+ return *lhsKey == *rhsKey;
+ }
}
+ return false;
}
bool operator!=(const Iterator& rhs) const
@@ -413,14 +466,22 @@ public:
bool operator==(const ConstIterator& rhs)
{
- if(_helper.get() != 0 && rhs._helper.get() != 0)
+ if(_helper.get() == rhs._helper.get())
{
- return _helper->equals(*rhs._helper);
+ return true;
}
- else
+
+ if(_helper.get() != 0 && rhs._helper.get() != 0)
{
- return _helper.get() == rhs._helper.get();
+ const Key* lhsKey = _helper->get();
+ const Key* rhsKey = rhs._helper->get();
+
+ if(lhsKey != 0 && rhsKey != 0)
+ {
+ return *lhsKey == *rhsKey;
+ }
}
+ return false;
}
bool operator!=(const ConstIterator& rhs)
@@ -565,21 +626,23 @@ public:
// Constructors
//
Map(const Freeze::ConnectionPtr& connection,
- const std::string& dbName,
- bool createDb = true) :
- _helper(MapHelper::create(connection, dbName, createDb)),
+ const std::string& dbName,
+ bool createDb = true) :
_communicator(connection->getCommunicator())
{
+ std::vector<MapIndexBasePtr> indices;
+ _helper.reset(MapHelper::create(connection, dbName, indices, createDb));
}
template <class _InputIterator>
Map(const Freeze::ConnectionPtr& connection,
- const std::string& dbName,
- bool createDb,
- _InputIterator first, _InputIterator last) :
- _helper(new MapHelper(connection, dbName, createDb)),
+ const std::string& dbName,
+ bool createDb,
+ _InputIterator first, _InputIterator last) :
_communicator(connection->getCommunicator())
{
+ std::vector<MapIndexBasePtr> indices;
+ _helper.reset(MapHelper::create(connection, dbName, indices, createDb));
while(first != last)
{
put(*first);
@@ -867,12 +930,111 @@ public:
}
-private:
+protected:
+
+ Map(const Ice::CommunicatorPtr& communicator) :
+ _communicator(communicator)
+ {
+ }
std::auto_ptr<MapHelper> _helper;
const Ice::CommunicatorPtr _communicator;
};
+
+//
+// ReverseMapIndex is used when the map's value is the secondary key
+//
+
+template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec>
+class ReverseMapIndex : public MapIndexBase
+{
+protected:
+
+ ReverseMapIndex(const std::string& name) :
+ MapIndexBase(name)
+ {
+ }
+
+ virtual void marshalKey(const Value& v, Key& k) const
+ {
+ k = v;
+ }
+};
+
+
+template <typename key_type, typename mapped_type, typename KeyCodec, typename ValueCodec>
+class MapWithReverseIndex : public Map<key_type, mapped_type, KeyCodec, ValueCodec>
+{
+public:
+
+ typedef std::pair<const key_type, const mapped_type> value_type;
+ typedef Iterator<key_type, mapped_type, KeyCodec, ValueCodec > iterator;
+ typedef ConstIterator<key_type, mapped_type, KeyCodec, ValueCodec > const_iterator;
+ typedef size_t size_type;
+ typedef ptrdiff_t difference_type;
+
+
+ //
+ // Constructors
+ //
+ MapWithReverseIndex(const Freeze::ConnectionPtr& connection,
+ const std::string& dbName,
+ bool createDb = true) :
+ Map<key_type, mapped_type, KeyCodec, ValueCodec>(connection->getCommunicator())
+ {
+ std::vector<MapIndexBasePtr> indices;
+ indices.push_back(new ReverseMapIndex<key_type, mapped_type, KeyCodec, ValueCodec>("index"));
+
+ _helper.reset(MapHelper::create(connection, dbName, indices, createDb));
+ }
+
+ template <class _InputIterator>
+ MapWithReverseIndex(const Freeze::ConnectionPtr& connection,
+ const std::string& dbName,
+ bool createDb,
+ _InputIterator first, _InputIterator last) :
+ Map<key_type, mapped_type, KeyCodec, ValueCodec>(connection->getCommunicator())
+ {
+ std::vector<MapIndexBasePtr> indices;
+ indices.push_back(new ReverseMapIndex<key_type, mapped_type, KeyCodec, ValueCodec>("index"));
+
+ while(first != last)
+ {
+ put(*first);
+ ++first;
+ }
+ }
+
+ //
+ // Extra functions
+ //
+
+ iterator reverseFind(const mapped_type& k)
+ {
+ Key bytes;
+ ValueCodec::write(k, bytes, _communicator);
+
+ return iterator(_helper->index("index")->untypedFind(bytes, false), _communicator);
+ }
+
+ const_iterator reverseFind(const mapped_type& k) const
+ {
+ Key bytes;
+ ValueCodec::write(k, bytes, _communicator);
+
+ return const_iterator(_helper->index("index")->untypedFind(bytes, true), _communicator);
+ }
+
+ int valueCount(const mapped_type& k) const
+ {
+ Key bytes;
+ ValueCodec::write(k, bytes, _communicator);
+
+ return _helper->index("index")->untypedCount(bytes);
+ }
+};
+
}
//
diff --git a/cpp/src/Freeze/IndexI.cpp b/cpp/src/Freeze/IndexI.cpp
index 0bef0002e7a..df1137a4269 100644
--- a/cpp/src/Freeze/IndexI.cpp
+++ b/cpp/src/Freeze/IndexI.cpp
@@ -308,13 +308,8 @@ Freeze::IndexI::secondaryKeyCreate(Db* secondary, const Dbt* dbKey,
{
Ice::CommunicatorPtr communicator = _store->communicator();
- Ice::Identity ident;
- Byte* first = static_cast<Byte*>(dbKey->get_data());
- Key key(first, first + dbKey->get_size());
- ObjectStore::unmarshal(ident, key, communicator);
-
ObjectRecord rec;
- first = static_cast<Byte*>(dbValue->get_data());
+ Byte* first = static_cast<Byte*>(dbValue->get_data());
Value value(first, first + dbValue->get_size());
ObjectStore::unmarshal(rec, value, communicator);
diff --git a/cpp/src/Freeze/MapI.cpp b/cpp/src/Freeze/MapI.cpp
index 7e39199f794..5470f27d9e0 100644
--- a/cpp/src/Freeze/MapI.cpp
+++ b/cpp/src/Freeze/MapI.cpp
@@ -19,16 +19,50 @@ using namespace Freeze;
//
+// MapIndexBase (from Map.h)
+//
+
+Freeze::MapIndexBase::~MapIndexBase()
+{
+}
+
+Freeze::MapIndexBase::MapIndexBase(const string& name) :
+ _name(name),
+ _impl(0),
+ _map(0)
+{
+}
+
+const string&
+MapIndexBase::name() const
+{
+ return _name;
+}
+
+IteratorHelper*
+Freeze::MapIndexBase::untypedFind(const Key& k, bool ro) const
+{
+ return _impl->untypedFind(k, ro, *_map);
+}
+
+int
+Freeze::MapIndexBase::untypedCount(const Key& k) const
+{
+ return _impl->untypedCount(k, _map->connection());
+}
+
+//
// MapHelper (from Map.h)
//
Freeze::MapHelper*
Freeze::MapHelper::create(const Freeze::ConnectionPtr& connection,
const string& dbName,
+ const std::vector<MapIndexBasePtr>& indices,
bool createDb)
{
Freeze::ConnectionIPtr connectionI = Freeze::ConnectionIPtr::dynamicCast(connection);
- return new MapHelperI(connectionI, dbName, createDb);
+ return new MapHelperI(connectionI, dbName, indices, createDb);
}
Freeze::MapHelper::~MapHelper()
@@ -45,8 +79,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));
- if(r->findFirst())
+ auto_ptr<IteratorHelperI> r(new IteratorHelperI(actualMap, readOnly, 0));
+ if(r->next())
{
return r.release();
}
@@ -62,21 +96,25 @@ Freeze::IteratorHelper::~IteratorHelper()
}
-
//
// IteratorHelperI
//
-
-Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) :
+Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly,
+ const MapIndexBasePtr& index) :
_map(m),
_dbc(0),
+ _indexed(index != 0),
_tx(0)
{
if(_map._trace >= 2)
{
Trace out(_map._connection->communicator()->getLogger(), "Freeze.Map");
out << "opening iterator on Db \"" << _map._dbName << "\"";
+ if(index != 0)
+ {
+ out << " with index \"" << index->name() << "\"";
+ }
}
DbTxn* txn = _map._connection->dbTxn();
@@ -92,7 +130,14 @@ Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) :
try
{
- _map._db->cursor(txn, &_dbc, 0);
+ if(index != 0)
+ {
+ index->_impl->db()->cursor(txn, &_dbc, 0);
+ }
+ else
+ {
+ _map._db->cursor(txn, &_dbc, 0);
+ }
}
catch(const ::DbException& dx)
{
@@ -100,12 +145,15 @@ Freeze::IteratorHelperI::IteratorHelperI(const MapHelperI& m, bool readOnly) :
ex.message = dx.what();
throw ex;
}
+
_map._iteratorList.push_back(this);
}
+
Freeze::IteratorHelperI::IteratorHelperI(const IteratorHelperI& it) :
_map(it._map),
_dbc(0),
+ _indexed(it._indexed),
_tx(0)
{
if(_map._trace >= 2)
@@ -134,11 +182,6 @@ Freeze::IteratorHelperI::~IteratorHelperI()
close();
}
-bool
-Freeze::IteratorHelperI::findFirst() const
-{
- return next();
-}
bool
Freeze::IteratorHelperI::find(const Key& key) const
@@ -217,7 +260,22 @@ Freeze::IteratorHelperI::get(const Key*& key, const Value*& value) const
{
try
{
- int err = _dbc->get(&dbKey, &dbValue, DB_CURRENT);
+ int err;
+
+ if(_indexed)
+ {
+ //
+ // Not interested in getting the index's key
+ //
+ Dbt iKey;
+ iKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+ err = _dbc->pget(&iKey, &dbKey, &dbValue, DB_CURRENT);
+ }
+ else
+ {
+ err = _dbc->get(&dbKey, &dbValue, DB_CURRENT);
+ }
if(err == 0)
{
@@ -314,7 +372,21 @@ Freeze::IteratorHelperI::get() const
{
try
{
- int err = _dbc->get(&dbKey, &dbValue, DB_CURRENT);
+ int err;
+ if(_indexed)
+ {
+ //
+ // Not interested in getting the index's key
+ //
+ Dbt iKey;
+ iKey.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+ err = _dbc->pget(&iKey, &dbKey, &dbValue, DB_CURRENT);
+ }
+ else
+ {
+ err = _dbc->get(&dbKey, &dbValue, DB_CURRENT);
+ }
if(err == 0)
{
@@ -377,6 +449,13 @@ Freeze::IteratorHelperI::get() const
void
Freeze::IteratorHelperI::set(const Value& value)
{
+ if(_indexed)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "Cannot set an iterator retrieved through an index";
+ throw ex;
+ }
+
//
// key ignored
//
@@ -463,9 +542,11 @@ Freeze::IteratorHelperI::next() const
Dbt dbValue;
dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+ int flags = _indexed ? DB_NEXT_DUP : DB_NEXT;
+
try
{
- if(_dbc->get(&dbKey, &dbValue, DB_NEXT) == 0)
+ if(_dbc->get(&dbKey, &dbValue, flags) == 0)
{
return true;
}
@@ -493,30 +574,6 @@ Freeze::IteratorHelperI::next() const
}
}
-bool
-Freeze::IteratorHelperI::equals(const IteratorHelper& rhs) const
-{
- if(this == &rhs)
- {
- return true;
- }
- else
- {
- //
- // Compare keys
- //
- try
- {
- Key rhsKey = *dynamic_cast<const IteratorHelperI&>(rhs).get();
- return *get() == rhsKey;
- }
- catch(const InvalidPositionException&)
- {
- return false;
- }
- }
-}
-
void
Freeze::IteratorHelperI::close()
{
@@ -654,12 +711,26 @@ Freeze::IteratorHelperI::Tx::dead()
Freeze::MapHelperI::MapHelperI(const ConnectionIPtr& connection,
const std::string& dbName,
+ const vector<MapIndexBasePtr>& indices,
bool createDb) :
_connection(connection),
- _db(SharedDb::get(connection, dbName, createDb)),
+ _db(SharedDb::get(connection, dbName, indices, createDb)),
_dbName(dbName),
_trace(connection->trace())
{
+ for(vector<MapIndexBasePtr>::const_iterator p = indices.begin();
+ p != indices.end(); ++p)
+ {
+ const MapIndexBasePtr& indexBase = *p;
+ assert(indexBase->_impl != 0);
+ assert(indexBase->_map == 0);
+ bool inserted =
+ _indices.insert(IndexMap::value_type(indexBase->name(), indexBase)).second;
+ assert(inserted);
+ indexBase->_map = this;
+ indexBase->_communicator = _connection->communicator();
+ }
+
_connection->registerMap(this);
}
@@ -675,7 +746,7 @@ Freeze::MapHelperI::find(const Key& k, bool readOnly) const
{
try
{
- auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly));
+ auto_ptr<IteratorHelperI> r(new IteratorHelperI(*this, readOnly, 0));
if(r->find(k))
{
return r.release();
@@ -995,6 +1066,19 @@ Freeze::MapHelperI::closeAllIterators()
}
}
+const MapIndexBasePtr&
+Freeze::MapHelperI::index(const string& name) const
+{
+ IndexMap::const_iterator p = _indices.find(name);
+ if(p == _indices.end())
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "Cannot find index \"" + name + "\"";
+ throw ex;
+ }
+ return p->second;
+}
+
void
Freeze::MapHelperI::close()
{
@@ -1003,6 +1087,15 @@ Freeze::MapHelperI::close()
_connection->unregisterMap(this);
}
_db = 0;
+
+ for(IndexMap::iterator p = _indices.begin(); p != _indices.end(); ++p)
+ {
+ MapIndexBasePtr& indexBase = p->second;
+
+ indexBase->_impl = 0;
+ indexBase->_map = 0;
+ }
+ _indices.clear();
}
void
@@ -1026,6 +1119,183 @@ Freeze::MapHelperI::closeAllIteratorsExcept(const IteratorHelperI::TxPtr& tx) co
}
}
+
+//
+// MapIndexI
+//
+
+static int
+callback(Db* secondary, const Dbt* key, const Dbt* value, Dbt* result)
+{
+ void* indexObj = secondary->get_app_private();
+ MapIndexI* index = static_cast<MapIndexI*>(indexObj);
+ assert(index != 0);
+ return index->secondaryKeyCreate(secondary, key, value, result);
+}
+
+
+Freeze::MapIndexI::MapIndexI(const ConnectionIPtr& connection, SharedDb& db,
+ DbTxn* txn, bool createDb, const MapIndexBasePtr& index) :
+ _index(index)
+{
+ assert(txn != 0);
+
+ _db.reset(new Db(connection->dbEnv(), 0));
+ _db->set_flags(DB_DUP | DB_DUPSORT);
+ _db->set_app_private(this);
+
+ u_int32_t flags = 0;
+ if(createDb)
+ {
+ flags = DB_CREATE;
+ }
+
+ _dbName = db.dbName() + "." + _index->name();
+
+ _db->open(txn, _dbName.c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE);
+
+ //
+ // To populate empty indices
+ //
+ flags = DB_CREATE;
+ db.associate(txn, _db.get(), callback, flags);
+
+ //
+ // Note: caller catch and translates exceptions
+ //
+}
+
+Freeze::MapIndexI::~MapIndexI()
+{
+ _db->close(0);
+}
+
+IteratorHelper*
+Freeze::MapIndexI::untypedFind(const Key& k, bool ro, const MapHelperI& map) const
+{
+ auto_ptr<IteratorHelperI> r(new IteratorHelperI(map, ro, _index));
+
+ if(r->find(k))
+ {
+ return r.release();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+int
+Freeze::MapIndexI::untypedCount(const Key& k, const ConnectionIPtr& connection) const
+{
+ Dbt dbKey;
+ initializeInDbt(k, dbKey);
+
+ Dbt dbValue;
+ dbValue.set_flags(DB_DBT_USERMEM | DB_DBT_PARTIAL);
+
+ int result = 0;
+
+ try
+ {
+ for(;;)
+ {
+ Dbc* dbc = 0;
+
+ try
+ {
+ //
+ // Move to the first record
+ //
+ _db->cursor(0, &dbc, 0);
+ bool found = (dbc->get(&dbKey, &dbValue, DB_SET) == 0);
+
+ if(found)
+ {
+ db_recno_t count = 0;
+ dbc->count(&count, 0);
+ result = static_cast<int>(count);
+ }
+
+ Dbc* toClose = dbc;
+ dbc = 0;
+ toClose->close();
+ break; // for (;;)
+ }
+ catch(const DbDeadlockException&)
+ {
+ if(dbc != 0)
+ {
+ try
+ {
+ dbc->close();
+ }
+ catch(const DbDeadlockException&)
+ {
+ //
+ // Ignored
+ //
+ }
+ }
+
+ if(connection->deadlockWarning())
+ {
+ Warning out(connection->communicator()->getLogger());
+ out << "Deadlock in Freeze::MapIndexI::untypedCount while searching \""
+ << _dbName << "\"; retrying ...";
+ }
+
+ //
+ // Retry
+ //
+ }
+ catch(...)
+ {
+ if(dbc != 0)
+ {
+ try
+ {
+ dbc->close();
+ }
+ catch(const DbDeadlockException&)
+ {
+ //
+ // Ignored
+ //
+ }
+ }
+ throw;
+ }
+ }
+ }
+ catch(const DbException& dx)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = dx.what();
+ throw ex;
+ }
+
+ return result;
+}
+
+int
+Freeze::MapIndexI::secondaryKeyCreate(Db* secondary, const Dbt* dbKey,
+ const Dbt* dbValue, Dbt* result)
+{
+ Byte* first = static_cast<Byte*>(dbValue->get_data());
+ Value value(first, first + dbValue->get_size());
+
+ Key bytes;
+ _index->marshalKey(value, bytes);
+
+ result->set_flags(DB_DBT_APPMALLOC);
+ void* data = malloc(bytes.size());
+ memcpy(data, &bytes[0], bytes.size());
+ result->set_data(data);
+ result->set_size(static_cast<u_int32_t>(bytes.size()));
+ return 0;
+}
+
//
// Print for the various exception types.
//
diff --git a/cpp/src/Freeze/MapI.h b/cpp/src/Freeze/MapI.h
index 2bb28cf1b24..6c60c1f55e9 100644
--- a/cpp/src/Freeze/MapI.h
+++ b/cpp/src/Freeze/MapI.h
@@ -23,23 +23,19 @@ class IteratorHelperI : public IteratorHelper
{
public:
- IteratorHelperI(const MapHelperI& m, bool readOnly);
-
+ IteratorHelperI(const MapHelperI& m, bool readOnly, const MapIndexBasePtr& index);
IteratorHelperI(const IteratorHelperI&);
virtual
~IteratorHelperI();
-
- bool
- findFirst() const;
-
+
bool
find(const Key& k) const;
virtual IteratorHelper*
clone() const;
- const Key*
+ virtual const Key*
get() const;
virtual void
@@ -54,9 +50,6 @@ public:
virtual bool
next() const;
- virtual bool
- equals(const IteratorHelper&) const;
-
void
close();
@@ -90,9 +83,9 @@ private:
void
cleanup();
-
const MapHelperI& _map;
Dbc* _dbc;
+ const bool _indexed;
TxPtr _tx;
mutable Key _key;
@@ -105,7 +98,7 @@ class MapHelperI : public MapHelper
public:
MapHelperI(const ConnectionIPtr& connection, const std::string& dbName,
- bool createDb);
+ const std::vector<MapIndexBasePtr>&, bool createDb);
virtual ~MapHelperI();
@@ -132,16 +125,26 @@ public:
virtual void
closeAllIterators();
+
+ virtual const MapIndexBasePtr&
+ index(const std::string&) const;
void
close();
+ const ConnectionIPtr& connection() const
+ {
+ return _connection;
+ }
+
+
+ typedef std::map<std::string, MapIndexBasePtr> IndexMap;
+
private:
virtual void
closeAllIteratorsExcept(const IteratorHelperI::TxPtr&) const;
-
friend class IteratorHelperI;
friend class IteratorHelperI::Tx;
@@ -149,9 +152,12 @@ private:
mutable std::list<IteratorHelperI*> _iteratorList;
SharedDbPtr _db;
const std::string _dbName;
+ IndexMap _indices;
+
Ice::Int _trace;
};
+
inline const IteratorHelperI::TxPtr&
IteratorHelperI::tx() const
{
diff --git a/cpp/src/Freeze/SharedDb.cpp b/cpp/src/Freeze/SharedDb.cpp
index 62c0e0cd6e3..4cb75641f89 100644
--- a/cpp/src/Freeze/SharedDb.cpp
+++ b/cpp/src/Freeze/SharedDb.cpp
@@ -28,7 +28,9 @@ Freeze::SharedDb::Map* Freeze::SharedDb::sharedDbMap = 0;
Freeze::SharedDbPtr
Freeze::SharedDb::get(const ConnectionIPtr& connection,
- const string& dbName, bool createDb)
+ const string& dbName,
+ const vector<MapIndexBasePtr>& indices,
+ bool createDb)
{
StaticMutex::Lock lock(_mapMutex);
@@ -46,6 +48,7 @@ Freeze::SharedDb::get(const ConnectionIPtr& connection,
Map::iterator p = sharedDbMap->find(key);
if(p != sharedDbMap->end())
{
+ p->second->connectIndices(indices);
return p->second;
}
}
@@ -53,7 +56,7 @@ Freeze::SharedDb::get(const ConnectionIPtr& connection,
//
// MapKey not found, let's create and open a new Db
//
- auto_ptr<SharedDb> result(new SharedDb(key, connection, createDb));
+ auto_ptr<SharedDb> result(new SharedDb(key, connection, indices, createDb));
//
// Insert it into the map
@@ -73,17 +76,7 @@ Freeze::SharedDb::~SharedDb()
out << "closing Db \"" << _key.dbName << "\"";
}
- try
- {
- close(0);
- }
- catch(const ::DbException& dx)
- {
- DatabaseException ex(__FILE__, __LINE__);
- ex.message = dx.what();
- throw ex;
- }
-
+ cleanup(false);
}
void Freeze::SharedDb::__incRef()
@@ -145,10 +138,10 @@ void Freeze::SharedDb::__decRef()
}
}
-
Freeze::SharedDb::SharedDb(const MapKey& key,
const ConnectionIPtr& connection,
+ const vector<MapIndexBasePtr>& indices,
bool createDb) :
Db(connection->dbEnv(), 0),
_key(key),
@@ -161,19 +154,148 @@ Freeze::SharedDb::SharedDb(const MapKey& key,
out << "opening Db \"" << _key.dbName << "\"";
}
+ DbTxn* txn = 0;
+ DbEnv* dbEnv = connection->dbEnv();
+
try
{
- u_int32_t flags = DB_AUTO_COMMIT | DB_THREAD;
+ dbEnv->txn_begin(0, &txn, 0);
+
+ u_int32_t flags = DB_THREAD;
if(createDb)
{
flags |= DB_CREATE;
}
- open(0, key.dbName.c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE);
+ open(txn, key.dbName.c_str(), 0, DB_BTREE, flags, FREEZE_DB_MODE);
+
+ for(vector<MapIndexBasePtr>::const_iterator p = indices.begin();
+ p != indices.end(); ++p)
+ {
+ const MapIndexBasePtr& indexBase = *p;
+
+ if(indexBase->_impl != 0)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "Index \"" + indexBase->name() + "\" already initialized!";
+ throw ex;
+ }
+
+ auto_ptr<MapIndexI> indexI(new MapIndexI(connection, *this, txn, createDb, indexBase));
+
+ bool inserted = _indices.insert(IndexMap::value_type(indexBase->name(), indexI.get())).second;
+ if(!inserted)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "Index \"" + indexBase->name() + "\" listed twice!";
+ throw ex;
+ }
+
+ indexBase->_impl = indexI.release();
+ }
+
+ DbTxn* toCommit = txn;
+ txn = 0;
+ toCommit->commit(0);
}
catch(const ::DbException& dx)
{
+ if(txn != 0)
+ {
+ try
+ {
+ txn->abort();
+ }
+ catch(...)
+ {
+ }
+ }
+
+ cleanup(true);
+
+ if(dx.get_errno() == ENOENT)
+ {
+ NotFoundException ex(__FILE__, __LINE__);
+ ex.message = dx.what();
+ throw ex;
+ }
+ else
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = dx.what();
+ throw ex;
+ }
+
DatabaseException ex(__FILE__, __LINE__);
ex.message = dx.what();
throw ex;
}
+ catch(...)
+ {
+ if(txn != 0)
+ {
+ try
+ {
+ txn->abort();
+ }
+ catch(...)
+ {
+ }
+ }
+
+ cleanup(true);
+ throw;
+ }
+}
+
+void
+Freeze::SharedDb::connectIndices(const vector<MapIndexBasePtr>& indices) const
+{
+ for(vector<MapIndexBasePtr>::const_iterator p = indices.begin();
+ p != indices.end(); ++p)
+ {
+ const MapIndexBasePtr& indexBase = *p;
+
+ if(indexBase->_impl != 0)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "Index \"" + indexBase->name() + "\" already initialized!";
+ throw ex;
+ }
+
+ IndexMap::const_iterator q = _indices.find(indexBase->name());
+
+ if(q == _indices.end())
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = "\"" + _key.dbName + "\" already opened but without index \""
+ + indexBase->name() +"\"";
+ throw ex;
+ }
+
+ indexBase->_impl = q->second;
+ }
+}
+
+void
+Freeze::SharedDb::cleanup(bool noThrow)
+{
+ try
+ {
+ for(IndexMap::iterator p = _indices.begin(); p != _indices.end(); ++p)
+ {
+ delete p->second;
+ }
+ _indices.clear();
+
+ close(0);
+ }
+ catch(const ::DbException& dx)
+ {
+ if(!noThrow)
+ {
+ DatabaseException ex(__FILE__, __LINE__);
+ ex.message = dx.what();
+ throw ex;
+ }
+ }
}
diff --git a/cpp/src/Freeze/SharedDb.h b/cpp/src/Freeze/SharedDb.h
index 9aa2b9a776e..406916541d7 100644
--- a/cpp/src/Freeze/SharedDb.h
+++ b/cpp/src/Freeze/SharedDb.h
@@ -13,6 +13,7 @@
#include <IceUtil/Config.h>
#include <db_cxx.h>
#include <Freeze/ConnectionI.h>
+#include <Freeze/Map.h>
#include <IceUtil/Handle.h>
#include <map>
@@ -22,13 +23,47 @@ namespace Freeze
class SharedDb;
typedef IceUtil::Handle<SharedDb> SharedDbPtr;
+class MapIndexI
+{
+public:
+
+ MapIndexI(const ConnectionIPtr&, SharedDb&,
+ DbTxn*, bool, const MapIndexBasePtr&);
+
+ ~MapIndexI();
+
+ IteratorHelper* untypedFind(const Key&, bool, const MapHelperI&) const;
+ int untypedCount(const Key&, const ConnectionIPtr&) const;
+
+ int
+ secondaryKeyCreate(Db*, const Dbt*, const Dbt*, Dbt*);
+
+ const std::string name() const
+ {
+ return _index->name();
+ }
+
+ Db* db() const
+ {
+ return _db.get();
+ }
+
+private:
+
+ const MapIndexBasePtr _index;
+ std::auto_ptr<Db> _db;
+ std::string _dbName;
+};
+
+
class SharedDb : public ::Db
{
public:
using Db::get;
- static SharedDbPtr get(const ConnectionIPtr&, const std::string&, bool);
+ static SharedDbPtr get(const ConnectionIPtr&, const std::string&,
+ const std::vector<MapIndexBasePtr>&, bool);
~SharedDb();
@@ -47,6 +82,8 @@ public:
}
#endif
+ typedef std::map<std::string, MapIndexI*> IndexMap;
+
private:
struct MapKey
@@ -61,12 +98,18 @@ private:
typedef std::map<MapKey, Freeze::SharedDb*> Map;
- SharedDb(const MapKey&, const ConnectionIPtr&, bool);
+ SharedDb(const MapKey&, const ConnectionIPtr&,
+ const std::vector<MapIndexBasePtr>&, bool);
+ void connectIndices(const std::vector<MapIndexBasePtr>&) const;
+ void cleanup(bool);
+
MapKey _key;
int _refCount;
Ice::Int _trace;
+ IndexMap _indices;
+
static Map* sharedDbMap;
};
diff --git a/cpp/src/slice2freeze/Main.cpp b/cpp/src/slice2freeze/Main.cpp
index 59baaff2c16..457c062a85e 100644
--- a/cpp/src/slice2freeze/Main.cpp
+++ b/cpp/src/slice2freeze/Main.cpp
@@ -15,11 +15,19 @@ using namespace std;
using namespace IceUtil;
using namespace Slice;
+struct DictIndex
+{
+ string member;
+ bool caseSensitive;
+};
+
struct Dict
{
string name;
string key;
string value;
+
+ vector<DictIndex> indices;
};
struct Index
@@ -57,6 +65,14 @@ 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"
+ " 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"
+ " VALUE. Otherwise, the entire VALUE is used for \n"
+ " indexing. When the secondary key is a string, \n"
+ " the case can be sensitive or insensitive (default\n"
+ " is sensitive).\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"
@@ -110,7 +126,7 @@ printFreezeTypes(Output& out, const vector<Dict>& dicts, const vector<Index>& in
void
writeCodecH(const TypePtr& type, const string& name, const string& freezeType, Output& H, const string& dllExport)
{
- H << sp << nl << dllExport << "class " << name;
+ H << sp << nl << "class " << dllExport << name;
H << sb;
H.dec();
H << sp << nl << "public:";
@@ -176,8 +192,335 @@ writeCodecC(const TypePtr& type, const string& name, const string& freezeType, b
C << eb;
}
+void
+writeDictWithIndicesH(const string& name, const Dict& dict,
+ const vector<TypePtr> indexTypes,
+ const TypePtr& keyType, const TypePtr& valueType,
+ Output& H, const string& dllExport)
+{
+
+ string templateParams = string("< ") + typeToString(keyType) + ", "
+ + typeToString(valueType) + ", " + name + "KeyCodec, "
+ + name + "ValueCodec>";
+
+ vector<string> capitalizedMembers;
+ size_t i;
+ for(i = 0; i < dict.indices.size(); ++i)
+ {
+ const string& member = dict.indices[i].member;
+ if(!member.empty())
+ {
+ string capitalizedMember = member;
+ capitalizedMember[0] = toupper(capitalizedMember[0]);
+ capitalizedMembers.push_back(capitalizedMember);
+ }
+ else
+ {
+ capitalizedMembers.push_back("Value");
+ }
+ }
+
+ H << sp << nl << "class " << dllExport << name
+ << " : public Freeze::Map" << templateParams;
+ H << sb;
+ H.dec();
+ H << sp << nl << "public:";
+ H << sp;
+ H.inc();
+
+ //
+ // Typedefs
+ //
+ H << nl << "typedef std::pair<const " << typeToString(keyType)
+ << ", const" << typeToString(valueType) << "> value_type;";
+
+ H << nl << "typedef Freeze::Iterator" << templateParams << " iterator;";
+ 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";
+ H << sb;
+
+ H.dec();
+ H << sp << nl << "public:";
+ H << sp;
+ H.inc();
+ H << nl << capitalizedMembers[i] << "Index(const std::string&);";
+
+ H << sp;
+ H << nl << "static void writeIndex(" << inputTypeToString(indexTypes[i])
+ << ", Freeze::Key&, const Ice::CommunicatorPtr&);";
+
+
+ H.dec();
+ H << sp << nl << "protected:";
+ H << sp;
+ H.inc();
+
+ H << nl << "virtual void marshalKey(const Freeze::Value&, Freeze::Key&) const;";
+
+ H << eb << ';';
+ }
+
+ //
+ // Constructors
+ //
+ H << sp;
+ H << nl << name << "(const Freeze::ConnectionPtr&, const std::string&, bool = true);";
+ H << sp;
+ H << nl << "template <class _InputIterator>"
+ << nl << name << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName, bool __createDb, "
+ << "_InputIterator __first, _InputIterator __last)";
+ H.inc();
+ H << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())";
+ H.dec();
+ H << sb;
+ H << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;";
+ for(i = 0; i < capitalizedMembers.size(); ++i)
+ {
+ string indexName = dict.indices[i].member;
+ if(indexName.empty())
+ {
+ indexName = "index";
+ }
+ indexName = string("\"") + indexName + "\"";
+
+ H << nl << "__indices.push_back(new " << capitalizedMembers[i] << "Index(" << indexName << "));";
+ }
+ H << nl << "_helper.reset(Freeze::MapHelper::create(__connection, __dbName, __indices, __createDb));";
+ H << nl << "while(__first != __last)";
+ H << sb;
+ H << nl << "put(*__first);";
+ H << nl << "++__first;";
+ H << eb;
+ H << eb;
+
+ //
+ // Find and count functions
+ //
+ for(i = 0; i < capitalizedMembers.size(); ++i)
+ {
+ H << sp;
+ H << nl << "iterator findBy" << capitalizedMembers[i]
+ << "(" << inputTypeToString(indexTypes[i]) << ");";
+ H << nl << "const_iterator findBy" << capitalizedMembers[i]
+ << "(" << inputTypeToString(indexTypes[i]) << ") const;";
+
+ string countFunction = dict.indices[i].member.empty() ? "valueCount"
+ : dict.indices[i].member + "Count";
+
+ H << nl << "int " << countFunction
+ << "(" << inputTypeToString(indexTypes[i]) << ") const;";
+ }
+
+ H << eb << ';';
+}
+
+void
+writeDictWithIndicesC(const string& name, const string& absolute, const Dict& dict,
+ const vector<TypePtr> indexTypes,
+ const TypePtr& keyType, const TypePtr& valueType,
+ Output& C)
+{
+ string templateParams = string("< ") + typeToString(keyType) + ", "
+ + typeToString(valueType) + ", " + name + "KeyCodec, "
+ + name + "ValueCodec>";
+
+ vector<string> capitalizedMembers;
+ size_t i;
+ for(i = 0; i < dict.indices.size(); ++i)
+ {
+ const string& member = dict.indices[i].member;
+ if(!member.empty())
+ {
+ string capitalizedMember = member;
+ capitalizedMember[0] = toupper(capitalizedMember[0]);
+ capitalizedMembers.push_back(capitalizedMember);
+ }
+ else
+ {
+ capitalizedMembers.push_back("Value");
+ }
+ }
+
+
+ //
+ // Nested index classes
+ //
+
+ for(i = 0; i < capitalizedMembers.size(); ++i)
+ {
+ string className = capitalizedMembers[i] + "Index";
+
+ C << sp << nl << absolute << "::" << className << "::" << className
+ << "(const std::string& __name)";
+
+ C.inc();
+ C << nl << ": Freeze::MapIndexBase(__name)";
+ C.dec();
+ C << sb;
+ C << eb;
+
+ C << sp << nl << "void"
+ << nl << absolute << "::" << className << "::"
+ << "marshalKey(const Freeze::Value& __v, Freeze::Key& __k) const";
+ C << sb;
+
+ bool optimize = false;
+
+ if(dict.indices[i].member.empty() && dict.indices[i].caseSensitive)
+ {
+ optimize = true;
+ C << nl << "__k = __v;";
+ }
+ else
+ {
+ //
+ // Can't optimize
+ //
+ C << nl << typeToString(valueType) << " __x;";
+ C << nl << absolute << "ValueCodec::read(__x, __v, _communicator);";
+ string param = "__x";
+
+ if(!dict.indices[i].member.empty())
+ {
+ if(ClassDeclPtr::dynamicCast(valueType) != 0)
+ {
+ param += "->" + dict.indices[i].member;
+ }
+ else
+ {
+ param += "." + dict.indices[i].member;
+ }
+ }
+ C << nl << "writeIndex(" << param << ", __k, _communicator);";
+ }
+ C << eb;
+
+ C << sp << nl << "void"
+ << nl << absolute << "::" << className << "::"
+ << "writeIndex(" << inputTypeToString(indexTypes[i])
+ << " __index, Freeze::Key& __bytes, const Ice::CommunicatorPtr& __communicator)";
+ C << sb;
+
+ if(optimize)
+ {
+ C << nl << absolute << "ValueCodec::write(__index, __bytes, __communicator);";
+ }
+ else
+ {
+ C << nl << "IceInternal::InstancePtr __instance = IceInternal::getInstance(__communicator);";
+ C << nl << "IceInternal::BasicStream __stream(__instance.get());";
+
+ string valueS;
+ if(dict.indices[i].caseSensitive)
+ {
+ valueS = "__index";
+ }
+ else
+ {
+ C << nl << typeToString(indexTypes[i]) << " __lowerCaseIndex = __index;";
+ C << nl << "std::transform(__lowerCaseIndex.begin(), __lowerCaseIndex.end(), __lowerCaseIndex.begin(), tolower);";
+ valueS = "__lowerCaseIndex";
+ }
+
+ writeMarshalUnmarshalCode(C, indexTypes[i], valueS, true, "__stream", false);
+ if(indexTypes[i]->usesClasses())
+ {
+ C << nl << "__stream.writePendingObjects();";
+ }
+ C << nl << "__bytes.swap(__stream.b);";
+ }
+ C << eb;
+ }
+
+
+ //
+ // Constructor
+ //
+
+ C << sp << nl << absolute << "::" << name << "::" << name
+ << "(const Freeze::ConnectionPtr& __connection, const std::string& __dbName , bool __createDb)";
+
+ C.inc();
+ C << nl << ": Freeze::Map" << templateParams <<"(__connection->getCommunicator())";
+ C.dec();
+ C << sb;
+ C << nl << "std::vector<Freeze::MapIndexBasePtr> __indices;";
+ for(i = 0; i < capitalizedMembers.size(); ++i)
+ {
+ string indexName = dict.indices[i].member;
+ if(indexName.empty())
+ {
+ indexName = "index";
+ }
+ indexName = string("\"") + indexName + "\"";
+
+ C << nl << "__indices.push_back(new " << capitalizedMembers[i] << "Index(" << indexName << "));";
+ }
+ C << nl << "_helper.reset(Freeze::MapHelper::create(__connection, __dbName, __indices, __createDb));";
+ C << eb;
+
+ //
+ // Find and count functions
+ //
+ for(i = 0; i < capitalizedMembers.size(); ++i)
+ {
+ string indexClassName = capitalizedMembers[i] + "Index";
+
+ string indexName = dict.indices[i].member;
+ if(indexName.empty())
+ {
+ indexName = "index";
+ }
+ indexName = string("\"") + indexName + "\"";
+
+ C << sp << nl << absolute << "::iterator"
+ << nl << absolute << "::" << "findBy" << capitalizedMembers[i]
+ << "(" << inputTypeToString(indexTypes[i]) << " __index)";
+ C << sb;
+ C << nl << "Freeze::Key __bytes;";
+ C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);";
+ C << nl << "return iterator(_helper->index(" << indexName
+ << ")->untypedFind(__bytes, false), _communicator);";
+ C << eb;
+
+ C << sp << nl << absolute << "::const_iterator"
+ << nl << absolute << "::" << "findBy" << capitalizedMembers[i]
+ << "(" << inputTypeToString(indexTypes[i]) << " __index) const";
+ C << sb;
+ C << nl << "Freeze::Key __bytes;";
+ C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);";
+ C << nl << "return const_iterator(_helper->index(" << indexName
+ << ")->untypedFind(__bytes, true), _communicator);";
+ C << eb;
+
+ string countFunction = dict.indices[i].member.empty() ? "valueCount"
+ : dict.indices[i].member + "Count";
+
+ C << sp << nl << "int"
+ << nl << absolute << "::" << countFunction
+ << "(" << inputTypeToString(indexTypes[i]) << " __index) const";
+ C << sb;
+ C << nl << "Freeze::Key __bytes;";
+ C << nl << indexClassName << "::" << "writeIndex(__index, __bytes, _communicator);";
+ C << nl << "return _helper->index(" << indexName
+ << ")->untypedCount(__bytes);";
+ C << eb;
+ }
+}
+
+
bool
-writeCodecs(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C, const string& dllExport)
+writeDict(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C, const string& dllExport)
{
string absolute = dict.name;
if(absolute.find("::") == 0)
@@ -232,8 +575,102 @@ writeCodecs(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C,
writeCodecH(keyType, name + "KeyCodec", "Key", H, dllExport);
writeCodecH(valueType, name + "ValueCodec", "Value", H, dllExport);
- H << sp << nl << "typedef Freeze::Map< " << typeToString(keyType) << ", " << typeToString(valueType) << ", "
- << name << "KeyCodec, " << name << "ValueCodec> " << name << ";";
+ vector<TypePtr> indexTypes;
+
+ if(dict.indices.size() == 0)
+ {
+ H << sp << nl << "typedef Freeze::Map< " << typeToString(keyType) << ", " << typeToString(valueType) << ", "
+ << name << "KeyCodec, " << name << "ValueCodec> " << name << ";";
+ }
+ else
+ {
+ for(vector<DictIndex>::const_iterator p = dict.indices.begin();
+ p != dict.indices.end(); ++p)
+ {
+ const DictIndex& index = *p;
+ if(index.member.empty())
+ {
+ if(dict.indices.size() > 1)
+ {
+ cerr << n << ": bad index for dictionary `" << dict.name << "'" << endl;
+ return false;
+ }
+
+ if(index.caseSensitive == false)
+ {
+ //
+ // Let's check value is a string
+ //
+
+ BuiltinPtr builtInType = BuiltinPtr::dynamicCast(valueType);
+
+ if(builtInType == 0 || builtInType->kind() != Builtin::KindString)
+ {
+ cerr << n << ": VALUE is a `" << dict.value << "', not a string " << endl;
+ return false;
+ }
+ }
+ indexTypes.push_back(valueType);
+ }
+ else
+ {
+ DataMemberPtr dataMember = 0;
+ DataMemberList dataMembers;
+
+ ClassDeclPtr classDecl = ClassDeclPtr::dynamicCast(valueType);
+ if(classDecl != 0)
+ {
+ dataMembers = classDecl->definition()->allDataMembers();
+ }
+ else
+ {
+ StructPtr structDecl = StructPtr::dynamicCast(valueType);
+ if(structDecl == 0)
+ {
+ cerr << n << ": `" << dict.value << "' is neither a class nor a struct." << endl;
+ return false;
+ }
+ dataMembers = structDecl->dataMembers();
+ }
+ DataMemberList::const_iterator q = dataMembers.begin();
+ while(q != dataMembers.end() && dataMember == 0)
+ {
+ if((*q)->name() == index.member)
+ {
+ dataMember = *q;
+ }
+ else
+ {
+ ++q;
+ }
+ }
+
+ if(dataMember == 0)
+ {
+ cerr << n << ": The value of `" << dict.name << "' has no data member named `" << index.member << "'" << endl;
+ return false;
+ }
+
+ TypePtr dataMemberType = dataMember->type();
+
+ if(index.caseSensitive == false)
+ {
+ //
+ // Let's check member is a string
+ //
+ BuiltinPtr memberType = BuiltinPtr::dynamicCast(dataMemberType);
+ if(memberType == 0 || memberType->kind() != Builtin::KindString)
+ {
+ cerr << n << ": `" << index.member << "'is not a string " << endl;
+ return false;
+ }
+ }
+ indexTypes.push_back(dataMemberType);
+ }
+ }
+ writeDictWithIndicesH(name, dict, indexTypes, keyType, valueType, H, dllExport);
+ }
+
for(q = scope.begin(); q != scope.end(); ++q)
{
@@ -243,6 +680,11 @@ writeCodecs(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C,
writeCodecC(keyType, absolute + "KeyCodec", "Key", false, C);
writeCodecC(valueType, absolute + "ValueCodec", "Value", true, C);
+
+ if(indexTypes.size() > 0)
+ {
+ writeDictWithIndicesC(name, absolute, dict, indexTypes, keyType, valueType, C);
+ }
return true;
}
@@ -251,7 +693,7 @@ writeCodecs(const string& n, UnitPtr& u, const Dict& dict, Output& H, Output& C,
void
writeIndexH(const string& memberTypeString, const string& name, Output& H, const string& dllExport)
{
- H << sp << nl << dllExport << "class " << name
+ H << sp << nl << "class " << dllExport << name
<< " : public Freeze::Index";
H << sb;
H.dec();
@@ -464,6 +906,9 @@ writeIndex(const string& n, UnitPtr& u, const Index& index, Output& H, Output& C
return true;
}
+
+
+
int
main(int argc, char* argv[])
{
@@ -648,6 +1093,92 @@ main(int argc, char* argv[])
}
argc -= 2;
}
+ else if(strcmp(argv[idx], "--dict-index") == 0)
+ {
+ if(idx + 1 >= argc || argv[idx + 1][0] == '-')
+ {
+ cerr << argv[0] << ": argument expected for `" << argv[idx] << "'" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ string s = argv[idx + 1];
+ s.erase(remove_if(s.begin(), s.end(), ::isspace), s.end());
+
+ string dictName;
+ DictIndex index;
+ string::size_type pos;
+
+ string caseString = "case-sensitive";
+ pos = s.find(',');
+ if(pos != string::npos)
+ {
+ dictName = s.substr(0, pos);
+ s.erase(0, pos + 1);
+
+ pos = s.find(',');
+ if(pos != string::npos)
+ {
+ index.member = s.substr(0, pos);
+ s.erase(0, pos + 1);
+ caseString = s;
+ }
+ else
+ {
+ if(s == "case-sensitive" || s == "case-insensitive")
+ {
+ caseString = s;
+ }
+ else
+ {
+ index.member = s;
+ }
+ }
+ }
+ else
+ {
+ dictName = s;
+ }
+
+ if(dictName.empty())
+ {
+ cerr << argv[0] << ": " << argv[idx] << ": no dictionary specified" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ if(caseString != "case-sensitive" && caseString != "case-insensitive")
+ {
+ cerr << argv[0] << ": " << argv[idx]
+ << ": 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)
+ {
+ if(p->name == dictName)
+ {
+ p->indices.push_back(index);
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ cerr << argv[0] << ": " << argv[idx] << ": unknown dictionary" << endl;
+ usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ for(int i = idx ; i + 2 < argc ; ++i)
+ {
+ argv[i] = argv[i + 2];
+ }
+ argc -= 2;
+ }
else if(strcmp(argv[idx], "-h") == 0 || strcmp(argv[idx], "--help") == 0)
{
usage(argv[0]);
@@ -917,7 +1448,7 @@ main(int argc, char* argv[])
{
try
{
- if(!writeCodecs(argv[0], u, *p, H, C, dllExport))
+ if(!writeDict(argv[0], u, *p, H, C, dllExport))
{
u->destroy();
return EXIT_FAILURE;
@@ -949,6 +1480,7 @@ main(int argc, char* argv[])
return EXIT_FAILURE;
}
}
+
}
H << "\n\n#endif\n";
diff --git a/cpp/test/Freeze/dbmap/Client.cpp b/cpp/test/Freeze/dbmap/Client.cpp
index 54c2b289004..3b83d9de0d8 100644
--- a/cpp/test/Freeze/dbmap/Client.cpp
+++ b/cpp/test/Freeze/dbmap/Client.cpp
@@ -18,6 +18,7 @@
using namespace std;
using namespace Ice;
using namespace Freeze;
+using namespace Test;
// #define SHOW_EXCEPTIONS 1
@@ -485,6 +486,59 @@ run(const CommunicatorPtr& communicator, const string& envName, const string&dbN
}
cout << "ok" << endl;
+ cout << "testing index ... " << flush;
+ m.clear();
+ populateDB(connection, m);
+
+ size_t length = alphabet.size();
+ for(size_t j = 0; j < length; ++j)
+ {
+ p = m.findByValue(static_cast<Int>(j));
+ test(p != m.end());
+ test(p->first == alphabet[j]);
+ test(++p == m.end());
+ }
+
+ //
+ // 2 items at 17
+ //
+ m.put(ByteIntMap::value_type(alphabet[21], static_cast<Int>(17)));
+
+ p = m.findByValue(17);
+ test(p != m.end());
+ test(p->first == alphabet[17] || p->first == alphabet[21]);
+ test(++p != m.end());
+ test(p->first == alphabet[17] || p->first == alphabet[21]);
+ test(++p == m.end());
+ test(m.valueCount(17) == 2);
+
+ p = m.findByValue(17);
+ test(p != m.end());
+ m.erase(p);
+ test(++p != m.end());
+ test(p->first == alphabet[17] || p->first == alphabet[21]);
+ test(++p == m.end());
+ test(m.valueCount(17) == 1);
+
+ p = m.findByValue(17);
+ test(p != m.end());
+ test(p->first == alphabet[17] || p->first == alphabet[21]);
+
+ try
+ {
+ p.set(18);
+ test(false);
+ }
+ catch(const DatabaseException& ex)
+ {
+ // Expected
+ }
+ test(p->first == alphabet[17] || p->first == alphabet[21]);
+ test(++p == m.end());
+ test(m.valueCount(17) == 1);
+
+ cout << "ok " << endl;
+
cout << "testing concurrent access... " << flush;
m.clear();
populateDB(connection, m);
diff --git a/cpp/test/Freeze/dbmap/Makefile b/cpp/test/Freeze/dbmap/Makefile
index 519b298e451..991525f3e48 100644
--- a/cpp/test/Freeze/dbmap/Makefile
+++ b/cpp/test/Freeze/dbmap/Makefile
@@ -28,7 +28,7 @@ $(CLIENT): $(OBJS)
ByteIntMap.h ByteIntMap.cpp: $(SLICE2FREEZE)
rm -f ByteIntMap.h ByteIntMap.cpp
- $(SLICE2FREEZE) --dict ByteIntMap,byte,int ByteIntMap
+ $(SLICE2FREEZE) --dict Test::ByteIntMap,byte,int --dict-index Test::ByteIntMap ByteIntMap
clean::
rm -f ByteIntMap.h ByteIntMap.cpp
diff --git a/cpp/test/Freeze/dbmap/dbmap.dsp b/cpp/test/Freeze/dbmap/dbmap.dsp
index c9fba76b9a6..94a7ce4acb4 100644
--- a/cpp/test/Freeze/dbmap/dbmap.dsp
+++ b/cpp/test/Freeze/dbmap/dbmap.dsp
@@ -120,7 +120,7 @@ USERDEP__DUMMY="..\..\..\bin\slice2freeze.exe" "..\..\..\lib\slice.lib"
InputPath=dummy.ice
BuildCmds= \
- ..\..\..\bin\slice2freeze.exe --dict ByteIntMap,byte,int ByteIntMap \
+ ..\..\..\bin\slice2freeze.exe --dict Test::ByteIntMap,byte,int --dict-index Test::ByteIntMap ByteIntMap \
"ByteIntMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
@@ -137,8 +137,8 @@ USERDEP__DUMMY="..\..\..\bin\slice2freeze.exe"
InputPath=dummy.ice
BuildCmds= \
- ..\..\..\bin\slice2freeze.exe --dict ByteIntMap,byte,int ByteIntMap \
-
+ ..\..\..\bin\slice2freeze.exe --dict Test::ByteIntMap,byte,int --dict-index Test::ByteIntMap ByteIntMap \
+
"ByteIntMap.h" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
$(BuildCmds)