Merge lp:~stewart/drizzle/bug492391-i_s-concurrency into lp:~drizzle-trunk/drizzle/development

Proposed by Stewart Smith
Status: Rejected
Rejected by: Stewart Smith
Proposed branch: lp:~stewart/drizzle/bug492391-i_s-concurrency
Merge into: lp:~drizzle-trunk/drizzle/development
Diff against target: 183 lines (+61/-14)
3 files modified
drizzled/plugin/info_schema_table.h (+25/-3)
plugin/information_engine/information_cursor.cc (+24/-8)
plugin/information_engine/information_cursor.h (+12/-3)
To merge this branch: bzr merge lp:~stewart/drizzle/bug492391-i_s-concurrency
Reviewer Review Type Date Requested Status
Brian Aker Needs Fixing
Monty Taylor Pending
Jay Pipes Pending
Review via email: mp+17340@code.launchpad.net

This proposal supersedes a proposal from 2010-01-11.

To post a comment you must log in.
Revision history for this message
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal

Not the most ideal fix, but a minimal one that does actually make the code work.

Revision history for this message
Jay Pipes (jaypipes) wrote : Posted in a previous version of this proposal

Hi!

Some little things, one bigger thing. :)

The bigger thing, and I'm sure you've already thought about this, is the fact that for each call to an I_S table, the underlying table/view rows are copied into the InformationCursor::rows memory. This is clearly a suboptimal strategy, but I'm going to assume you've already discussed this with Brian?

Tiny style fixups:

77 + while(copy_iter != sch_table->getRows().end())

One space after while, please :)

There is some space/indent weirdness going on in the constructors (see below on diff). Indents should be 2 spaces (there is one area they are 4 spaces below.)

Unless there's a good reason not to do so, the general trend I've seen in the code is to have constructors and other method definitions be in the .cc files and not the .h files where they are implicitly inlined. You have the setup of the mutex attr and the mutex itself duplicated in both constructors and they are in the .h file. I'd prefer to see the mutex and mutex attr initialization put into an init() private method and see the constructors defined in the .cc file.

Also, the following lines should be reversed IMHO:

46 + pthread_mutex_destroy(&mutex);
47 + pthread_mutexattr_destroy(&mutex_attr);

The reason is that pthread_mutex_destroy() may invalidate the data at address &mutex_attr, and pthread_mutexattr_destroy() may return EINVAL. Not sure of the importance, but you may want to place (void) before both the calls...

Finally, instead of calling pthread_mutex_lock() directly, like in InformationCursor::rnd_init():

59 + pthread_mutex_lock(&sch_table->mutex);

it would be better to encapsulate the locking in a InfoSchemaTable::lock() method. This would make it much easier to change (for instance if you wanted to switch to a rwlock instead of a mutex...)

Cheers!

Jay

review: Needs Fixing
Revision history for this message
Stewart Smith (stewart) wrote : Posted in a previous version of this proposal

On Thu, Jan 07, 2010 at 04:05:19PM -0000, Jay Pipes wrote:
> Some little things, one bigger thing. :)
>
> The bigger thing, and I'm sure you've already thought about this, is
> the fact that for each call to an I_S table, the underlying table/view
> rows are copied into the InformationCursor::rows memory. This is
> clearly a suboptimal strategy, but I'm going to assume you've already
> discussed this with Brian?

This strategy is complete poo :)

It is, however, the simplest patch to get to working from where we can
fix things to actually not suck (that patch is... well.. huge).

> Tiny style fixups:
>
> 77 + while(copy_iter != sch_table->getRows().end())
>
> One space after while, please :)

i want a commit hook :)

> There is some space/indent weirdness going on in the constructors
> (see below on diff). Indents should be 2 spaces (there is one area
> they are 4 spaces below.)

hrrm... maybe emacs mode fail there.

> Unless there's a good reason not to do so, the general trend I've
> seen in the code is to have constructors and other method definitions
> be in the .cc files and not the .h files where they are implicitly
> inlined. You have the setup of the mutex attr and the mutex itself
> duplicated in both constructors and they are in the .h file. I'd
> prefer to see the mutex and mutex attr initialization put into an
> init() private method and see the constructors defined in the .cc file.

okay. not that much of a deal either way, but sure.

> Also, the following lines should be reversed IMHO:
>
> 46 + pthread_mutex_destroy(&mutex);
> 47 + pthread_mutexattr_destroy(&mutex_attr);
>
> The reason is that pthread_mutex_destroy() may invalidate the data
> at address &mutex_attr, and pthread_mutexattr_destroy() may return
> EINVAL. Not sure of the importance, but you may want to place (void)
> before both the calls...

interesting... where you get this info from?

> Finally, instead of calling pthread_mutex_lock() directly, like in InformationCursor::rnd_init():
>
> 59 + pthread_mutex_lock(&sch_table->mutex);
>
> it would be better to encapsulate the locking in a
> InfoSchemaTable::lock() method. This would make it much easier to
> change (for instance if you wanted to switch to a rwlock instead of a
> mutex...)

I don't want it to be misunderstood as a lock on the
InfoSchemaTable... just on the rows...

but i also don't want the code lasting more than a trivial amount of
time :)

--
Stewart Smith

Revision history for this message
Jay Pipes (jaypipes) wrote : Posted in a previous version of this proposal

Stewart Smith wrote:
> On Thu, Jan 07, 2010 at 04:05:19PM -0000, Jay Pipes wrote:
>> Some little things, one bigger thing. :)
>>
>> The bigger thing, and I'm sure you've already thought about this, is
>> the fact that for each call to an I_S table, the underlying table/view
>> rows are copied into the InformationCursor::rows memory. This is
>> clearly a suboptimal strategy, but I'm going to assume you've already
>> discussed this with Brian?
>
> This strategy is complete poo :)
>
> It is, however, the simplest patch to get to working from where we can
> fix things to actually not suck (that patch is... well.. huge).

OK, I figured as much :)

>> Also, the following lines should be reversed IMHO:
>>
>> 46 + pthread_mutex_destroy(&mutex);
>> 47 + pthread_mutexattr_destroy(&mutex_attr);
>>
>> The reason is that pthread_mutex_destroy() may invalidate the data
>> at address &mutex_attr, and pthread_mutexattr_destroy() may return
>> EINVAL. Not sure of the importance, but you may want to place (void)
>> before both the calls...
>
> interesting... where you get this info from?

Per this link:

http://docs.sun.com/app/docs/doc/802-1949/6i5ur8qam?a=view

"If a mutex is dynamically allocated and was initialized with an
attribute object, its attribute object should be freed with
pthread_mutexattr_destroy() before the mutex itself is freed."

>> Finally, instead of calling pthread_mutex_lock() directly, like in InformationCursor::rnd_init():
>>
>> 59 + pthread_mutex_lock(&sch_table->mutex);
>>
>> it would be better to encapsulate the locking in a
>> InfoSchemaTable::lock() method. This would make it much easier to
>> change (for instance if you wanted to switch to a rwlock instead of a
>> mutex...)
>
> I don't want it to be misunderstood as a lock on the
> InfoSchemaTable... just on the rows...

But it *is* essentially a lock on the whole object :)

> but i also don't want the code lasting more than a trivial amount of
> time :)

ack. :)

-jay

Revision history for this message
Jay Pipes (jaypipes) wrote : Posted in a previous version of this proposal

sweet. :)

review: Approve
Revision history for this message
Brian Aker (brianaker) wrote : Posted in a previous version of this proposal

In file included from plugin/innobase/handler/ha_innodb.cc:85:
./drizzled/plugin/info_schema_table.h: In member function 'void drizzled::plugin::InfoSchemaTable::init()':
./drizzled/plugin/info_schema_table.h:309: error: 'PTHREAD_MUTEX_RECURSIVE_NP' was not declared in this scope
gmake[2]: *** [plugin/innobase/handler/plugin_libinnobase_plugin_la-ha_innodb.lo] Error 1
gmake[2]: Leaving directory `/home/hudson/hudson/workspace/drizzle-build-freebsd-8.0'

Can you run your code through param build before submitting for inclusion?

Thanks!

review: Needs Fixing
Revision history for this message
Stewart Smith (stewart) wrote :

now ran through param build. seems to be okay everywhere.

Revision history for this message
Stewart Smith (stewart) wrote :

http://hudson.drizzle.org/job/Drizzle-param-ubuntu904-64bit/68/consoleFull

shows a func_gconcat failure.

I have logged into the exact same machine, built and run the tests (both debug and non-debug) and cannot at all reproduce this.

I currently theorize something to do with a dirty tree that is being used to build it through hudson.

Is someone able to blast away the dir for hudson and re-run the build?

Revision history for this message
Stewart Smith (stewart) wrote :

Ignore the above. Comment is on wrong branch.

Revision history for this message
Brian Aker (brianaker) wrote :

Another failure, from Gaz ->

main.information_schema [ fail ] timeout

Merge is also still failing.

review: Needs Fixing
Revision history for this message
Stewart Smith (stewart) wrote :

Going to mark this as rejected due to Brian's DATA_DICTIONARY work.

Unmerged revisions

1266. By Stewart Smith

need _XOPEN_SOURCE defined on Linux to get portable recursive mutex definition.

1265. By Stewart Smith

pthread.hneeds to be included in info_schema_table.h

1264. By Stewart Smith

move mutex init in InfoSchemaTable to private init() method and call from both constructors

1263. By Stewart Smith

free mutex attr before mutex. as per:

http://docs.sun.com/app/docs/doc/802-1949/6i5ur8qam?a=view

"If a mutex is dynamically allocated and was initialized with an
attribute object, its attribute object should be freed with
pthread_mutexattr_destroy() before the mutex itself is freed."

1262. By Stewart Smith

Rows in the I_S plugin object make it not thread safe. Due to the way we do subselects, it's also recursive (fillTable can call fillTable).... so we have a recursive mutex.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'drizzled/plugin/info_schema_table.h'
2--- drizzled/plugin/info_schema_table.h 2010-01-06 02:20:42 +0000
3+++ drizzled/plugin/info_schema_table.h 2010-01-14 02:20:23 +0000
4@@ -29,6 +29,10 @@
5 #include <string>
6 #include <set>
7 #include <algorithm>
8+#ifndef _XOPEN_SOURCE
9+#define _XOPEN_SOURCE 500 // for portable recursive mutex definition on linux
10+#endif
11+#include <pthread.h>
12
13 class Session;
14 class TableList;
15@@ -301,11 +305,23 @@
16 InfoSchemaTable();
17 InfoSchemaTable(const InfoSchemaTable &);
18 InfoSchemaTable& operator=(const InfoSchemaTable &);
19+
20+private:
21+ void init()
22+ {
23+ pthread_mutexattr_init(&mutex_attr);
24+ pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
25+ pthread_mutex_init(&mutex, &mutex_attr);
26+ }
27+
28 public:
29
30 typedef std::vector<const ColumnInfo *> Columns;
31 typedef std::vector<InfoSchemaRecord *> Rows;
32-
33+
34+ pthread_mutex_t mutex;
35+ pthread_mutexattr_t mutex_attr;
36+
37 InfoSchemaTable(const std::string& tab_name,
38 Columns& in_column_info,
39 int idx_col1,
40@@ -324,7 +340,9 @@
41 column_info(in_column_info),
42 rows(),
43 i_s_methods(in_methods)
44- {}
45+ {
46+ init();
47+ }
48
49 explicit InfoSchemaTable(const std::string& tab_name)
50 :
51@@ -337,7 +355,9 @@
52 column_info(),
53 rows(),
54 i_s_methods(NULL)
55- {}
56+ {
57+ init();
58+ }
59
60 virtual ~InfoSchemaTable()
61 {
62@@ -345,6 +365,8 @@
63 rows.end(),
64 DeleteRows());
65 rows.clear();
66+ pthread_mutexattr_destroy(&mutex_attr);
67+ pthread_mutex_destroy(&mutex);
68 }
69
70 /**
71
72=== modified file 'plugin/information_engine/information_cursor.cc'
73--- plugin/information_engine/information_cursor.cc 2010-01-06 02:20:42 +0000
74+++ plugin/information_engine/information_cursor.cc 2010-01-14 02:20:23 +0000
75@@ -61,6 +61,8 @@
76 int InformationCursor::rnd_init(bool)
77 {
78 plugin::InfoSchemaTable *sch_table= share->getInfoSchemaTable();
79+ pthread_mutex_lock(&sch_table->mutex);
80+
81 if (sch_table)
82 {
83 if (! sch_table->getRows().empty())
84@@ -69,8 +71,24 @@
85 }
86 sch_table->fillTable(ha_session(),
87 table);
88- iter= sch_table->getRows().begin();
89+
90+ std::for_each(rows.begin(),
91+ rows.end(),
92+ plugin::DeleteRows());
93+ rows.clear();
94+
95+ plugin::InfoSchemaTable::Rows::iterator copy_iter= sch_table->getRows().begin();
96+
97+ while(copy_iter != sch_table->getRows().end())
98+ {
99+ rows.push_back(new plugin::InfoSchemaRecord(*(*copy_iter)));
100+ copy_iter++;
101+ }
102+
103+ iter= rows.begin();
104 }
105+ pthread_mutex_unlock(&sch_table->mutex);
106+
107 return 0;
108 }
109
110@@ -78,10 +96,9 @@
111 int InformationCursor::rnd_next(unsigned char *buf)
112 {
113 ha_statistic_increment(&SSV::ha_read_rnd_next_count);
114- plugin::InfoSchemaTable *sch_table= share->getInfoSchemaTable();
115
116- if (iter != sch_table->getRows().end() &&
117- ! sch_table->getRows().empty())
118+ if (iter != rows.end() &&
119+ ! rows.empty())
120 {
121 (*iter)->copyRecordInto(buf);
122 ++iter;
123@@ -122,11 +139,10 @@
124 memcpy(&cs, pos, sizeof(uint32_t));
125
126 /* search for that data */
127- plugin::InfoSchemaTable *sch_table= share->getInfoSchemaTable();
128- plugin::InfoSchemaTable::Rows::iterator it= find_if(sch_table->getRows().begin(),
129- sch_table->getRows().end(),
130+ plugin::InfoSchemaTable::Rows::iterator it= find_if(rows.begin(),
131+ rows.end(),
132 FindRowByChecksum(cs));
133- if (it != sch_table->getRows().end())
134+ if (it != rows.end())
135 {
136 (*it)->copyRecordInto(buf);
137 }
138
139=== modified file 'plugin/information_engine/information_cursor.h'
140--- plugin/information_engine/information_cursor.h 2009-12-22 08:05:32 +0000
141+++ plugin/information_engine/information_cursor.h 2010-01-14 02:20:23 +0000
142@@ -33,10 +33,16 @@
143 THR_LOCK_DATA lock; /* MySQL lock */
144 InformationEngine::Share *share;
145 drizzled::plugin::InfoSchemaTable::Rows::iterator iter;
146+ drizzled::plugin::InfoSchemaTable::Rows rows;
147
148 public:
149 InformationCursor(drizzled::plugin::StorageEngine &engine, TableShare &table_arg);
150- ~InformationCursor() {}
151+ ~InformationCursor() {
152+ std::for_each(rows.begin(),
153+ rows.end(),
154+ drizzled::plugin::DeleteRows());
155+ rows.clear();
156+}
157
158 int open(const char *name, int mode, uint32_t test_if_locked);
159
160@@ -60,19 +66,22 @@
161 */
162 ha_rows estimate_rows_upper_bound()
163 {
164+ ha_rows retval= HA_POS_ERROR;
165 if (share)
166 {
167 drizzled::plugin::InfoSchemaTable *sch_table= share->getInfoSchemaTable();
168 if (sch_table)
169 {
170+ pthread_mutex_lock(&sch_table->mutex);
171 if (! sch_table->getRows().empty())
172 {
173 /* we multiply by 3 here to ensure enough memory is allocated for sort buffers */
174- return (3 * sch_table->getRows().size());
175+ retval= 3 * sch_table->getRows().size();
176 }
177+ pthread_mutex_unlock(&sch_table->mutex);
178 }
179 }
180- return HA_POS_ERROR;
181+ return retval;
182 }
183 };
184