File: MetadataItem_invalidation.txt

package info (click to toggle)
flamerobin 0.7.6-2
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 3,956 kB
  • ctags: 6,032
  • sloc: cpp: 37,019; sh: 2,688; xml: 1,073; makefile: 510
file content (221 lines) | stat: -rw-r--r-- 8,702 bytes parent folder | download | duplicates (10)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
Nando wrote:

Hello,
I would like to rationalize the way metadata items load their state
from the database; currently YTable has loadColumns() and
checkAndLockColumns(), YProcedure has loadParameters() and
checkLoadParameters(), I myself have just added something similar
(loadProperties()) to YException, etc.

I was thinking of bringing all this under the umbrella of
YxMetadataItem, with the following semantics:

// invalidates everything the item has read from the database;
// this means that next time a property is requested it will be
// read anew from the database.
// Some classes might support selective invalidation of portions
// of data (e.g. "columns", or "indexes"), and that's what
// propertySetName is for. By default, invaliate() invalidates
// everything and calls notify().
void YxMetadataItem::invalidate(std::string propertySetName = "");

The item would keep one of more internal flags to account for what's
invalidated and reload it on request.

For a sample of the benefits of the approach, this code excerpt from
database.cpp:

if (t == ntTable || t == ntView)
    result = ((YxMetadataItemWithColumns *)object)->loadColumns();
else if (t == ntProcedure)
    result = ((YProcedure *)object)->checkAndLoadParameters();
else if (t == ntException)
    ((YException *)object)->loadProperties(true);
else
    object->notify();

(to which I have just contributed the third branch, BTW) would become:

object->invalidate();

Comments? Remarks? Better ideas?

Milan replied:

| I would like to rationalize the way metadata items load their state
| from the database; currently YTable has loadColumns() and
| checkAndLockColumns(), YProcedure has loadParameters() and
| checkLoadParameters(), I myself have just added something similar
| (loadProperties()) to YException, etc.
|
| I was thinking of bringing all this under the umbrella of
| YxMetadataItem, with the following semantics:
|
| // invalidates everything the item has read from the database;
[snip]

Very good.

I have thought that something like this will soon be needed anyway.

| // By default, invaliate() invalidates
| // everything and calls notify().

We would have to be careful about this so we don't enter the endless
loop. I guess we can use the locking mechanism that is already there.

| For a sample of the benefits of the approach, this code excerpt from
| database.cpp:
|
| if (t == ntTable || t == ntView)
|     result = ((YxMetadataItemWithColumns *)object)->loadColumns();
| else if (t == ntProcedure)
|     result = ((YProcedure *)object)->checkAndLoadParameters();
| else if (t == ntException)
|     ((YException *)object)->loadProperties(true);
| else
|     object->notify();
|
| (to which I have just contributed the third branch, BTW) would become:
|
| object->invalidate();

Well, not really since for tables/view/procedures you only have to
invalidate columns/parameters (exactly what you wrote about: selective
invalidation).

Anyway, I fully agree what you wrote. We can have a parameter to
invalidate() which will specify what is invalidated. Some objects would
consider it, others ignore.

One more remark: table->invalidate(columns) doesn't have to call
notify() since reloading of columns will do that anyway, so a locking
mechanism should really be used.

Nando replied:

M> | For a sample of the benefits of the approach, this code excerpt from
M> | database.cpp:
M> |
M> | if (t == ntTable || t == ntView)
M> |     result = ((YxMetadataItemWithColumns *)object)->loadColumns();
M> | else if (t == ntProcedure)
M> |     result = ((YProcedure *)object)->checkAndLoadParameters();
M> | else if (t == ntException)
M> |     ((YException *)object)->loadProperties(true);
M> | else
|     object->>notify();
M> |
M> | (to which I have just contributed the third branch, BTW) would become:
M> |
| object->>invalidate();

M> Well, not really since for tables/view/procedures you only have to
M> invalidate columns/parameters (exactly what you wrote about: selective
M> invalidation).

aren't columns/parameters all that those objects hold anyway? Huh
no, tables have also constraints, for example. This needs a bit more
thought...

<more thought>

Premise: the code above comes from database.cpp, and it runs
when an executed SQL (mostly DDL) statement is parsed by YDatabase to
see if any objects need refreshing.

The problem is that only the metadata object itself knows ultimately
what should be invalidated as a result of executing a SQL statement,
so the solution is to let all metadata objects in turn have a peek at
the statement and let each of them do whatever is needed to. IOW
instead of letting the YDatabase govern everything, we use a
cooperative network to achieve the same. This can be implemented at
different degrees depending on the level of efficiency (did I say
that? <g>) we want to achieve:

a) the YDatabase hands the SQL statement off to each metadata object
it holds in turn. Each metadata collection hands it to the items it
contains (look, here's another reason for having concrete metadata
collections!). This could be wasteful as potentially many items would
need to parse the statement again and again. I said "could" because we
might well be talking about millisecond-scale delays anyway.

b) the YDatabase pre-parses the statement, finds the object kind and
name (as it already does), locates the relevant metadata object and
hands it the statement. This is slightly less flexible but probably
faster.

c) <???>

Note: in many cases the SQL statement itself comes from a metadata
object from the beginning. In other cases the user typed it freely in
the SQL window. If we didn't have to support the latter scenario then
a simpler variant of option b would be enough and the YDatabase
wouldn't even be involved at all. But we do have to support it, right?

M> One more remark: table->invalidate(columns) doesn't have to call
M> notify() since reloading of columns will do that anyway, so a locking
M> mechanism should really be used.

In perspective I would even like to make notify() protected, so that
each object deals with this stuff on its own. You just call a setXXX()
member function and it sees by itself what's to
invalidate/lock/notify, etc.

Milan replied:

| M> Well, not really since for tables/view/procedures you only have to
| M> invalidate columns/parameters (exactly what you wrote about: selective
| M> invalidation).
|
| aren't columns/parameters all that those objects hold anyway? Huh
| no, tables have also constraints, for example

Yep, and tables views might also get some links to triggers too.

| a) the YDatabase hands the SQL statement off to each metadata object
| it holds in turn. Each metadata collection hands it to the items it
| contains (look, here's another reason for having concrete metadata
| collections!). This could be wasteful as potentially many items would
| need to parse the statement again and again. I said "could" because we
| might well be talking about millisecond-scale delays anyway.

Not needed IMHO.

| b) the YDatabase pre-parses the statement, finds the object kind and
| name (as it already does), locates the relevant metadata object and
| hands it the statement. This is slightly less flexible but probably
| faster.

I think this will do. Also, note that DROP statements should be handles
by YDatabase, so if it is going to parse the string anyway, we can use
it for other things too.

| c) <???>

Maybe the same as b) but send the parsed pieces too? Although I haven't
got the idea how to do that cleanly.

| Note: in many cases the SQL statement itself comes from a metadata
| object from the beginning. In other cases the user typed it freely in
| the SQL window. If we didn't have to support the latter scenario then
| a simpler variant of option b would be enough and the YDatabase
| wouldn't even be involved at all. But we do have to support it, right?

It's a must. User could always type some ALTER (or some other) statement
that we don't provide via GUI, and object should refresh. Also, this way
we can centralize all DDL processing, and make logging stuff easy. It
also let's various program parts just dump SQL into ExecuteSqlFrame and
don't "think" about it.

| M> One more remark: table->invalidate(columns) doesn't have to call
| M> notify() since reloading of columns will do that anyway, so a locking
| M> mechanism should really be used.
|
| In perspective I would even like to make notify() protected, so that
| each object deals with this stuff on its own. You just call a setXXX()
| member function and it sees by itself what's to
| invalidate/lock/notify, etc.

Maybe not a bad idea. I can't foresee how will it work in practice
though. I guess we will have to test and see.