8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-23 15:23:02 +01:00

Use explicit iterators instead of the implicit (built-in) ones due to the thread-safety requirements.

This change affects GenericMap only, as it's used globally in a few places and we have a proven crash there.
I have a more complete solution (total cleanup of default accessors from BePlusTree and SparseBitmap) in my local tree (thanks to Dmitry Kovalenko), but it's incomplete (requires more changes inside the engine) and IMHO risky (~20 core modules are affected), so I'd like to defer finalization of this cleanup till v3.0.
All objects of these types seem being protected by dbb_sync, so they shouldn't cause us any problems currently.
This commit is contained in:
dimitr 2008-12-19 14:57:01 +00:00
parent a8df21db11
commit 2b87e94242
9 changed files with 124 additions and 69 deletions

View File

@ -57,9 +57,32 @@ public:
typedef typename KeyValuePair::first_type KeyType; typedef typename KeyValuePair::first_type KeyType;
typedef typename KeyValuePair::second_type ValueType; typedef typename KeyValuePair::second_type ValueType;
typedef BePlusTree<KeyValuePair*, KeyType, MemoryPool, FirstObjectKey<KeyValuePair>, KeyComparator> ValuesTree;
class Accessor
{
public:
Accessor(GenericMap* map) : m_Accessor(&map->tree) {}
KeyValuePair* current() const { return m_Accessor.current(); }
bool getFirst() { return m_Accessor.getFirst(); }
bool getNext() { return m_Accessor.getNext(); }
private:
Accessor(const Accessor&);
Accessor& operator=(const Accessor&);
typename ValuesTree::Accessor m_Accessor;
};
friend class Accessor;
GenericMap() : tree(&getPool()), mCount(0) { } GenericMap() : tree(&getPool()), mCount(0) { }
explicit GenericMap(MemoryPool& a_pool) explicit GenericMap(MemoryPool& a_pool)
: AutoStorage(a_pool), tree(&getPool()), mCount(0) { } : AutoStorage(a_pool), tree(&getPool()), mCount(0) { }
~GenericMap() ~GenericMap()
{ {
clear(); clear();
@ -69,23 +92,29 @@ public:
{ {
clear(); clear();
for (bool found = v.getFirst(); found; found = v.getNext()) GenericMap::Accessor accessor(&v);
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
{ {
KeyValuePair* current_pair = v.current(); const KeyValuePair* const current_pair = accessor.current();
put(current_pair->first, current_pair->second); put(current_pair->first, current_pair->second);
} }
} }
void takeOwnership(GenericMap& from) void takeOwnership(GenericMap& from)
{ {
fb_assert(this != &from);
clear(); clear();
tree = from.tree; tree = from.tree;
mCount = from.mCount; mCount = from.mCount;
if (from.tree.getFirst()) { ValuesTree::Accessor treeAccessor(&from.tree);
if (treeAccessor.getFirst()) {
while (true) { while (true) {
bool haveMore = from.tree.fastRemove(); bool haveMore = treeAccessor.fastRemove();
if (!haveMore) if (!haveMore)
break; break;
} }
@ -97,10 +126,12 @@ public:
// Clear the map // Clear the map
void clear() void clear()
{ {
if (tree.getFirst()) { ValuesTree::Accessor treeAccessor(&tree);
if (treeAccessor.getFirst()) {
while (true) { while (true) {
KeyValuePair* temp = tree.current(); KeyValuePair* temp = treeAccessor.current();
bool haveMore = tree.fastRemove(); bool haveMore = treeAccessor.fastRemove();
delete temp; delete temp;
if (!haveMore) if (!haveMore)
break; break;
@ -113,9 +144,11 @@ public:
// Returns true if value existed // Returns true if value existed
bool remove(const KeyType& key) bool remove(const KeyType& key)
{ {
if (tree.locate(key)) { ValuesTree::Accessor treeAccessor(&tree);
KeyValuePair* var = tree.current();
tree.fastRemove(); if (treeAccessor.locate(key)) {
KeyValuePair* var = treeAccessor.current();
treeAccessor.fastRemove();
delete var; delete var;
mCount--; mCount--;
return true; return true;
@ -127,8 +160,10 @@ public:
// Returns true if value existed previously // Returns true if value existed previously
bool put(const KeyType& key, const ValueType& value) bool put(const KeyType& key, const ValueType& value)
{ {
if (tree.locate(key)) { ValuesTree::Accessor treeAccessor(&tree);
tree.current()->second = value;
if (treeAccessor.locate(key)) {
treeAccessor.current()->second = value;
return true; return true;
} }
@ -141,8 +176,10 @@ public:
// Returns pointer to the added empty value or null when key already exists // Returns pointer to the added empty value or null when key already exists
ValueType* put(const KeyType& key) ValueType* put(const KeyType& key)
{ {
if (tree.locate(key)) { ValuesTree::Accessor treeAccessor(&tree);
return 0;
if (treeAccessor.locate(key)) {
return NULL;
} }
KeyValuePair* var = FB_NEW(getPool()) KeyValuePair(getPool()); KeyValuePair* var = FB_NEW(getPool()) KeyValuePair(getPool());
@ -155,32 +192,35 @@ public:
// Returns true if value is found // Returns true if value is found
bool get(const KeyType& key, ValueType& value) bool get(const KeyType& key, ValueType& value)
{ {
if (tree.locate(key)) { ValuesTree::Accessor treeAccessor(&tree);
value = tree.current()->second;
if (treeAccessor.locate(key)) {
value = treeAccessor.current()->second;
return true; return true;
} }
return false; return false;
} }
bool getFirst() { return tree.getFirst(); } // Returns pointer to the found value or null otherwise
ValueType* get(const KeyType& key)
{
ValuesTree::Accessor treeAccessor(&tree);
bool getLast() { return tree.getLast(); } if (treeAccessor.locate(key)) {
return &treeAccessor.current()->second;
}
bool getNext() { return tree.getNext(); } return NULL;
}
bool getPrev() { return tree.getPrev(); }
KeyValuePair* current() const { return tree.current(); }
bool exist(const KeyType& key) bool exist(const KeyType& key)
{ {
return tree.locate(key); return ValuesTree::Accessor(&tree).locate(key);
} }
size_t count() const { return mCount; } size_t count() const { return mCount; }
typedef BePlusTree<KeyValuePair*, KeyType, MemoryPool, FirstObjectKey<KeyValuePair>, KeyComparator> ValuesTree;
private: private:
ValuesTree tree; ValuesTree tree;
size_t mCount; size_t mCount;

View File

@ -1210,7 +1210,9 @@ void DatabaseSnapshot::putContextVars(Firebird::StringMap& variables,
Firebird::ClumpletWriter& writer, Firebird::ClumpletWriter& writer,
int object_id, bool is_attachment) int object_id, bool is_attachment)
{ {
for (bool found = variables.getFirst(); found; found = variables.getNext()) StringMap::Accessor accessor(&variables);
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
{ {
writer.insertByte(TAG_RECORD, rel_mon_ctx_vars); writer.insertByte(TAG_RECORD, rel_mon_ctx_vars);
@ -1219,8 +1221,8 @@ void DatabaseSnapshot::putContextVars(Firebird::StringMap& variables,
else else
writer.insertInt(f_mon_ctx_var_tra_id, object_id); writer.insertInt(f_mon_ctx_var_tra_id, object_id);
writer.insertString(f_mon_ctx_var_name, variables.current()->first); writer.insertString(f_mon_ctx_var_name, accessor.current()->first);
writer.insertString(f_mon_ctx_var_value, variables.current()->second); writer.insertString(f_mon_ctx_var_value, accessor.current()->second);
} }
} }

View File

@ -58,10 +58,10 @@ namespace
~ModulesMap() ~ModulesMap()
{ {
// unload modules // unload modules
for (bool found = getFirst(); found; found = getNext()) Accessor accessor(this);
for (bool found = accessor.getFirst(); found; found = accessor.getNext())
{ {
ModuleLoader::Module* module = current()->second; delete accessor.current()->second;
delete module;
} }
} }
}; };

View File

@ -77,7 +77,9 @@ static ULONG unicodeCanonical(texttype* tt, ULONG srcLen, const UCHAR* src,
string IntlUtil::generateSpecificAttributes( string IntlUtil::generateSpecificAttributes(
Jrd::CharSet* cs, SpecificAttributesMap& map) Jrd::CharSet* cs, SpecificAttributesMap& map)
{ {
bool found = map.getFirst(); SpecificAttributesMap::Accessor accessor(&map);
bool found = accessor.getFirst();
string s; string s;
while (found) while (found)
@ -85,7 +87,7 @@ string IntlUtil::generateSpecificAttributes(
UCHAR c[sizeof(ULONG)]; UCHAR c[sizeof(ULONG)];
ULONG size; ULONG size;
SpecificAttribute* attribute = map.current(); SpecificAttribute* attribute = accessor.current();
s += escapeAttribute(cs, attribute->first); s += escapeAttribute(cs, attribute->first);
@ -99,7 +101,7 @@ string IntlUtil::generateSpecificAttributes(
s += escapeAttribute(cs, attribute->second); s += escapeAttribute(cs, attribute->second);
found = map.getNext(); found = accessor.getNext();
if (found) if (found)
{ {
@ -420,7 +422,9 @@ bool IntlUtil::initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name
IntlUtil::SpecificAttributesMap map16; IntlUtil::SpecificAttributesMap map16;
bool found = map.getFirst(); SpecificAttributesMap::Accessor accessor(&map);
bool found = accessor.getFirst();
while (found) while (found)
{ {
@ -429,20 +433,20 @@ bool IntlUtil::initUnicodeCollation(texttype* tt, charset* cs, const ASCII* name
ULONG errPosition; ULONG errPosition;
s1.resize(cs->charset_to_unicode.csconvert_fn_convert( s1.resize(cs->charset_to_unicode.csconvert_fn_convert(
&cs->charset_to_unicode, map.current()->first.length(), NULL, 0, NULL, &errCode, &errPosition)); &cs->charset_to_unicode, accessor.current()->first.length(), NULL, 0, NULL, &errCode, &errPosition));
s1.resize(cs->charset_to_unicode.csconvert_fn_convert( s1.resize(cs->charset_to_unicode.csconvert_fn_convert(
&cs->charset_to_unicode, map.current()->first.length(), (UCHAR*) map.current()->first.c_str(), &cs->charset_to_unicode, accessor.current()->first.length(), (UCHAR*) accessor.current()->first.c_str(),
s1.getCapacity(), s1.begin(), &errCode, &errPosition)); s1.getCapacity(), s1.begin(), &errCode, &errPosition));
s2.resize(cs->charset_to_unicode.csconvert_fn_convert( s2.resize(cs->charset_to_unicode.csconvert_fn_convert(
&cs->charset_to_unicode, map.current()->second.length(), NULL, 0, NULL, &errCode, &errPosition)); &cs->charset_to_unicode, accessor.current()->second.length(), NULL, 0, NULL, &errCode, &errPosition));
s2.resize(cs->charset_to_unicode.csconvert_fn_convert( s2.resize(cs->charset_to_unicode.csconvert_fn_convert(
&cs->charset_to_unicode, map.current()->second.length(), (UCHAR*) map.current()->second.c_str(), &cs->charset_to_unicode, accessor.current()->second.length(), (UCHAR*) accessor.current()->second.c_str(),
s2.getCapacity(), s2.begin(), &errCode, &errPosition)); s2.getCapacity(), s2.begin(), &errCode, &errPosition));
map16.put(string((char*) s1.begin(), s1.getCount()), string((char*) s2.begin(), s2.getCount())); map16.put(string((char*) s1.begin(), s1.getCount()), string((char*) s2.begin(), s2.getCount()));
found = map.getNext(); found = accessor.getNext();
} }
UnicodeUtil::Utf16Collation* collation = UnicodeUtil::Utf16Collation* collation =

View File

@ -2031,26 +2031,27 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_f
csb->csb_node = CMP_pass1(tdbb, csb, csb->csb_node); csb->csb_node = CMP_pass1(tdbb, csb, csb->csb_node);
// Copy and compile (pass1) domains DEFAULT and constraints. // Copy and compile (pass1) domains DEFAULT and constraints.
bool found = csb->csb_map_field_info.getFirst();
while (found)
{ {
FieldInfo& fieldInfo = csb->csb_map_field_info.current()->second; MapFieldInfo::Accessor accessor(&csb->csb_map_field_info);
UCHAR local_map[MAP_LENGTH];
AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable, for (bool found = accessor.getFirst(); found; found = accessor.getNext())
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1); {
FieldInfo& fieldInfo = accessor.current()->second;
UCHAR local_map[MAP_LENGTH];
fieldInfo.defaultValue = copy(tdbb, csb, fieldInfo.defaultValue, local_map, 0, NULL, false); AutoSetRestore<USHORT> autoRemapVariable(&csb->csb_remap_variable,
(csb->csb_variables ? csb->csb_variables->count() : 0) + 1);
csb->csb_remap_variable = (csb->csb_variables ? csb->csb_variables->count() : 0) + 1; fieldInfo.defaultValue = copy(tdbb, csb, fieldInfo.defaultValue, local_map, 0, NULL, false);
fieldInfo.validation = copy(tdbb, csb, fieldInfo.validation, local_map, 0, NULL, false); csb->csb_remap_variable = (csb->csb_variables ? csb->csb_variables->count() : 0) + 1;
fieldInfo.defaultValue = CMP_pass1(tdbb, csb, fieldInfo.defaultValue); fieldInfo.validation = copy(tdbb, csb, fieldInfo.validation, local_map, 0, NULL, false);
fieldInfo.validation = CMP_pass1(tdbb, csb, fieldInfo.validation);
found = csb->csb_map_field_info.getNext(); fieldInfo.defaultValue = CMP_pass1(tdbb, csb, fieldInfo.defaultValue);
} fieldInfo.validation = CMP_pass1(tdbb, csb, fieldInfo.validation);
}
} // scope
csb->csb_impure = REQ_SIZE + REQ_TAIL * MAX(csb->csb_n_stream, 1); csb->csb_impure = REQ_SIZE + REQ_TAIL * MAX(csb->csb_n_stream, 1);
csb->csb_exec_sta.clear(); csb->csb_exec_sta.clear();
@ -2058,16 +2059,17 @@ jrd_req* CMP_make_request(thread_db* tdbb, CompilerScratch* csb, bool internal_f
csb->csb_node = CMP_pass2(tdbb, csb, csb->csb_node, 0); csb->csb_node = CMP_pass2(tdbb, csb, csb->csb_node, 0);
// Compile (pass2) domains DEFAULT and constraints // Compile (pass2) domains DEFAULT and constraints
found = csb->csb_map_field_info.getFirst();
while (found)
{ {
FieldInfo& fieldInfo = csb->csb_map_field_info.current()->second; MapFieldInfo::Accessor accessor(&csb->csb_map_field_info);
fieldInfo.defaultValue = CMP_pass2(tdbb, csb, fieldInfo.defaultValue, 0); for (bool found = accessor.getFirst(); found; found = accessor.getNext())
fieldInfo.validation = CMP_pass2(tdbb, csb, fieldInfo.validation, 0); {
FieldInfo& fieldInfo = accessor.current()->second;
found = csb->csb_map_field_info.getNext(); fieldInfo.defaultValue = CMP_pass2(tdbb, csb, fieldInfo.defaultValue, 0);
} fieldInfo.validation = CMP_pass2(tdbb, csb, fieldInfo.validation, 0);
}
} // scope
if (csb->csb_impure > MAX_REQUEST_SIZE) { if (csb->csb_impure > MAX_REQUEST_SIZE) {
IBERROR(226); // msg 226 request size limit exceeded IBERROR(226); // msg 226 request size limit exceeded

View File

@ -4888,10 +4888,10 @@ static void release_attachment(thread_db* tdbb, Attachment* attachment, ISC_STAT
if (attachment->att_temp_pg_lock) if (attachment->att_temp_pg_lock)
LCK_release(tdbb, attachment->att_temp_pg_lock); LCK_release(tdbb, attachment->att_temp_pg_lock);
for (bool getResult = attachment->att_dsql_cache.getFirst(); getResult; DSqlCache::Accessor accessor(&attachment->att_dsql_cache);
getResult = attachment->att_dsql_cache.getNext()) for (bool getResult = accessor.getFirst(); getResult; getResult = accessor.getNext())
{ {
LCK_release(tdbb, attachment->att_dsql_cache.current()->second.lock); LCK_release(tdbb, accessor.current()->second.lock);
} }
#endif #endif

View File

@ -228,6 +228,9 @@ struct DSqlCacheItem
bool obsolete; bool obsolete;
}; };
typedef Firebird::GenericMap<Firebird::Pair<Firebird::Left<
Firebird::string, DSqlCacheItem> > > DSqlCache;
// //
// the attachment block; one is created for each attachment to a database // the attachment block; one is created for each attachment to a database
@ -330,8 +333,7 @@ public:
#ifndef SUPERSERVER #ifndef SUPERSERVER
Lock* att_temp_pg_lock; // temporary pagespace ID lock Lock* att_temp_pg_lock; // temporary pagespace ID lock
#endif #endif
Firebird::GenericMap<Firebird::Pair<Firebird::Left< DSqlCache att_dsql_cache; // DSQL cache locks
Firebird::string, DSqlCacheItem> > > att_dsql_cache; // DSQL cache locks
Firebird::SortedArray<void*> att_udf_pointers; Firebird::SortedArray<void*> att_udf_pointers;
dsql_dbb* att_dsql_instance; dsql_dbb* att_dsql_instance;
Firebird::Mutex att_mutex; // attachment mutex Firebird::Mutex att_mutex; // attachment mutex

View File

@ -4192,7 +4192,9 @@ static DSqlCacheItem* get_dsql_cache_item(thread_db* tdbb, int type, const Fireb
memcpy(item->lock->lck_key.lck_string, key.c_str(), key.length()); memcpy(item->lock->lck_key.lck_string, key.c_str(), key.length());
} }
else else
item = &attachment->att_dsql_cache.current()->second; {
item = attachment->att_dsql_cache.get(key);
}
return item; return item;
} }

View File

@ -117,6 +117,8 @@ public:
// cache ICU module instances to not load and unload many times // cache ICU module instances to not load and unload many times
class UnicodeUtil::ICUModules class UnicodeUtil::ICUModules
{ {
typedef GenericMap<Pair<Left<string, ICU*> > > ModulesMap;
public: public:
explicit ICUModules(MemoryPool&) explicit ICUModules(MemoryPool&)
{ {
@ -124,11 +126,12 @@ public:
~ICUModules() ~ICUModules()
{ {
for (bool found = modules().getFirst(); found; found = modules().getNext()) ModulesMap::Accessor modulesAccessor(&modules());
delete modules().current()->second; for (bool found = modulesAccessor.getFirst(); found; found = modulesAccessor.getNext())
delete modulesAccessor.current()->second;
} }
InitInstance<GenericMap<Pair<Left<string, ICU*> > > > modules; InitInstance<ModulesMap> modules;
RWLock lock; RWLock lock;
}; };