Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 07f79e2

Browse files
committed
Fixed performance issues introduced with previous refactoring.
1 parent 99447ed commit 07f79e2

6 files changed

Lines changed: 183 additions & 152 deletions

source/core/output_buffers/ut_output_buffer_base.tpb

Lines changed: 40 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -64,100 +64,51 @@ create or replace type body ut_output_buffer_base is
6464
commit;
6565
end;
6666

67-
member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is
68-
lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 );
69-
lc_100_milisec constant number(1,1) := 0.1; --sleep for 100 ms between checks
70-
lc_500_milisec constant number(3,1) := 0.5; --sleep for 1 s when waiting long
71-
lc_1_second constant number(3,1) := 1;
72-
l_buffer_rowids ut_varchar2_rows;
73-
l_buffer_data ut_output_data_rows;
74-
l_finished_flags ut_integer_list;
75-
l_last_read_message_id integer;
76-
l_already_waited_sec number(10,2) := 0;
77-
l_data_finished boolean := false;
78-
l_finished boolean := false;
79-
l_sleep_time number(2,1) := lc_100_milisec;
80-
l_lock_status integer;
81-
l_producer_started boolean := false;
82-
l_producer_finished boolean := false;
83-
function get_lock_status return integer is
84-
l_result integer;
85-
l_release_status integer;
86-
begin
87-
l_result := dbms_lock.request( self.lock_handle, dbms_lock.s_mode, 0, false );
88-
if l_result = 0 then
89-
l_release_status := dbms_lock.release( self.lock_handle );
90-
end if;
91-
return l_result;
92-
end;
67+
member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean
68+
is
69+
l_result boolean := false;
9370
begin
94-
while not l_finished loop
95-
96-
--check if the lock is still there on output - if yes, the main session is still running and so don't stop
97-
l_lock_status := get_lock_status();
98-
get_data_from_buffer_table( l_last_read_message_id, l_buffer_data, l_buffer_rowids, l_finished_flags );
99-
100-
--nothing fetched from output, wait and try again
101-
if l_buffer_data.count = 0 then
102-
103-
dbms_lock.sleep(l_sleep_time);
104-
l_already_waited_sec := l_already_waited_sec + l_sleep_time;
105-
106-
-- if waited more than lc_1_second seconds then increase wait period to minimize the CPU usage.
107-
if l_already_waited_sec >= lc_1_second then
108-
l_sleep_time := lc_500_milisec;
109-
end if;
110-
71+
if not a_producer_started and a_already_waited_sec >= a_init_wait_sec then
72+
if a_init_wait_sec > 0 then
73+
self.remove_buffer_info();
74+
raise_application_error(
75+
ut_utils.gc_out_buffer_timeout,
76+
'Timeout occurred while waiting for report data producer to start. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.'
77+
);
11178
else
112-
113-
l_already_waited_sec := 0;
114-
l_sleep_time := lc_100_milisec;
115-
116-
for i in 1 .. l_buffer_data.count loop
117-
if l_buffer_data(i).text is not null then
118-
pipe row( l_buffer_data(i) );
119-
elsif l_finished_flags(i) = 1 then
120-
l_data_finished := true;
121-
exit;
122-
end if;
123-
end loop;
124-
125-
remove_read_data(l_buffer_rowids);
126-
79+
l_result := true;
12780
end if;
128-
l_producer_started := (l_lock_status <> 0 or l_buffer_data.count > 0) or l_producer_started;
129-
l_producer_finished := (l_producer_started and l_lock_status = 0 and l_buffer_data.count = 0) or l_producer_finished;
130-
131-
if not l_producer_started and l_already_waited_sec >= lc_init_wait_sec then
132-
133-
if lc_init_wait_sec > 0 then
134-
self.remove_buffer_info();
135-
raise_application_error(
136-
ut_utils.gc_out_buffer_timeout,
137-
'Timeout occurred while waiting for report data producer to start. Waited for: '||ut_utils.to_string( l_already_waited_sec )||' seconds.'
138-
);
139-
else
140-
l_finished := true;
141-
end if;
142-
143-
elsif not l_producer_finished and a_timeout_sec is not null and l_already_waited_sec >= a_timeout_sec then
144-
145-
if a_timeout_sec > 0 then
146-
self.remove_buffer_info();
147-
raise_application_error(
148-
ut_utils.gc_out_buffer_timeout,
149-
'Timeout occurred while waiting for more data from producer. Waited for: '||ut_utils.to_string( l_already_waited_sec )||' seconds.'
150-
);
151-
else
152-
l_finished := true;
153-
end if;
81+
end if;
82+
return l_result;
83+
end;
15484

155-
elsif (l_data_finished or l_producer_finished) then
156-
l_finished := true;
85+
member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean
86+
is
87+
l_result boolean := false;
88+
begin
89+
if not a_producer_finished and a_timeout_sec is not null and a_already_waited_sec >= a_timeout_sec then
90+
if a_timeout_sec > 0 then
91+
self.remove_buffer_info();
92+
raise_application_error(
93+
ut_utils.gc_out_buffer_timeout,
94+
'Timeout occurred while waiting for more data from producer. Waited for: '||ut_utils.to_string( a_already_waited_sec )||' seconds.'
95+
);
96+
else
97+
l_result := true;
15798
end if;
158-
end loop;
159-
self.remove_buffer_info();
160-
return;
99+
end if;
100+
return l_result;
101+
end;
102+
103+
member function get_lock_status return integer is
104+
l_result integer;
105+
l_release_status integer;
106+
begin
107+
l_result := dbms_lock.request( self.lock_handle, dbms_lock.s_mode, 0, false );
108+
if l_result = 0 then
109+
l_release_status := dbms_lock.release( self.lock_handle );
110+
end if;
111+
return l_result;
161112
end;
162113

163114
member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is

source/core/output_buffers/ut_output_buffer_base.tps

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,22 +24,17 @@ create or replace type ut_output_buffer_base force authid definer as object(
2424
self_type varchar2(250 byte),
2525
member procedure init(self in out nocopy ut_output_buffer_base, a_output_id raw := null, a_self_type varchar2 := null),
2626
member procedure lock_buffer(a_timeout_sec number := null),
27+
member function timeout_producer_not_started( a_producer_started boolean, a_already_waited_sec number, a_init_wait_sec number ) return boolean,
28+
member function timeout_producer_not_finished(a_producer_finished boolean, a_already_waited_sec number, a_timeout_sec number) return boolean,
29+
member function get_lock_status return integer,
2730
member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor,
2831
member procedure lines_to_dbms_output(self in ut_output_buffer_base, a_initial_timeout number := null, a_timeout_sec number := null),
2932
member procedure cleanup_buffer(self in ut_output_buffer_base, a_retention_time_sec natural := null),
3033
member procedure remove_buffer_info(self in ut_output_buffer_base),
31-
not instantiable member procedure get_data_from_buffer_table(
32-
self in ut_output_buffer_base,
33-
a_last_read_message_id in out nocopy integer,
34-
a_buffer_data out nocopy ut_output_data_rows,
35-
a_buffer_rowids out nocopy ut_varchar2_rows,
36-
a_finished_flags out nocopy ut_integer_list
37-
),
3834
member procedure close(self in out nocopy ut_output_buffer_base),
39-
not instantiable member procedure remove_read_data(self in ut_output_buffer_base, a_buffer_rowids ut_varchar2_rows),
4035
not instantiable member procedure send_line(self in out nocopy ut_output_buffer_base, a_text varchar2, a_item_type varchar2 := null),
4136
not instantiable member procedure send_lines(self in out nocopy ut_output_buffer_base, a_text_list ut_varchar2_rows, a_item_type varchar2 := null),
4237
not instantiable member procedure send_clob(self in out nocopy ut_output_buffer_base, a_text clob, a_item_type varchar2 := null),
43-
member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
38+
not instantiable member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
4439
) not final not instantiable
4540
/

source/core/output_buffers/ut_output_clob_table_buffer.tpb

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,86 @@ create or replace type body ut_output_clob_table_buffer is
5555
commit;
5656
end;
5757

58-
overriding member procedure get_data_from_buffer_table(
59-
self in ut_output_clob_table_buffer,
60-
a_last_read_message_id in out nocopy integer,
61-
a_buffer_data out nocopy ut_output_data_rows,
62-
a_buffer_rowids out nocopy ut_varchar2_rows,
63-
a_finished_flags out nocopy ut_integer_list
64-
) is
65-
lc_bulk_limit constant integer := 5000;
66-
begin
67-
a_last_read_message_id := coalesce(a_last_read_message_id, 0);
68-
with ordered_buffer as (
69-
select /*+ no_parallel index(a) */ ut_output_data_row(a.text, a.item_type), rowidtochar(a.rowid), is_finished
70-
from ut_output_clob_buffer_tmp a
71-
where a.output_id = self.output_id
72-
and a.message_id <= a_last_read_message_id + lc_bulk_limit
73-
order by a.message_id
74-
)
75-
select /*+ no_parallel */ b.*
76-
bulk collect into a_buffer_data, a_buffer_rowids, a_finished_flags
77-
from ordered_buffer b;
78-
a_last_read_message_id := a_last_read_message_id + a_finished_flags.count;
79-
end;
58+
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is
59+
lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 );
60+
l_buffer_rowids ut_varchar2_rows;
61+
l_buffer_data ut_output_data_rows;
62+
l_finished_flags ut_integer_list;
63+
l_last_read_message_id integer;
64+
l_already_waited_sec number(10,2) := 0;
65+
l_finished boolean := false;
66+
l_sleep_time number(2,1);
67+
l_lock_status integer;
68+
l_producer_started boolean := false;
69+
l_producer_finished boolean := false;
70+
procedure get_data_from_buffer_table(
71+
a_last_read_message_id in out nocopy integer,
72+
a_buffer_data out nocopy ut_output_data_rows,
73+
a_buffer_rowids out nocopy ut_varchar2_rows,
74+
a_finished_flags out nocopy ut_integer_list
75+
) is
76+
lc_bulk_limit constant integer := 5000;
77+
begin
78+
a_last_read_message_id := coalesce(a_last_read_message_id, 0);
79+
with ordered_buffer as (
80+
select /*+ no_parallel index(a) */ ut_output_data_row(a.text, a.item_type), rowidtochar(a.rowid), is_finished
81+
from ut_output_clob_buffer_tmp a
82+
where a.output_id = self.output_id
83+
and a.message_id <= a_last_read_message_id + lc_bulk_limit
84+
order by a.message_id
85+
)
86+
select /*+ no_parallel */ b.*
87+
bulk collect into a_buffer_data, a_buffer_rowids, a_finished_flags
88+
from ordered_buffer b;
89+
a_last_read_message_id := a_last_read_message_id + a_finished_flags.count;
90+
end;
91+
92+
procedure remove_read_data(a_buffer_rowids ut_varchar2_rows) is
93+
pragma autonomous_transaction;
94+
begin
95+
forall i in 1 .. a_buffer_rowids.count
96+
delete from ut_output_clob_buffer_tmp a
97+
where rowid = chartorowid(a_buffer_rowids(i));
98+
commit;
99+
end;
80100

81-
overriding member procedure remove_read_data(self in ut_output_clob_table_buffer, a_buffer_rowids ut_varchar2_rows) is
82-
pragma autonomous_transaction;
83101
begin
84-
forall i in 1 .. a_buffer_rowids.count
85-
delete from ut_output_clob_buffer_tmp a
86-
where rowid = chartorowid(a_buffer_rowids(i));
87-
commit;
102+
while not l_finished loop
103+
104+
l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end;
105+
l_lock_status := self.get_lock_status();
106+
get_data_from_buffer_table( l_last_read_message_id, l_buffer_data, l_buffer_rowids, l_finished_flags );
107+
108+
if l_buffer_data.count > 0 then
109+
l_already_waited_sec := 0;
110+
for i in 1 .. l_buffer_data.count loop
111+
if l_buffer_data(i).text is not null then
112+
pipe row( l_buffer_data(i) );
113+
elsif l_finished_flags(i) = 1 then
114+
l_finished := true;
115+
exit;
116+
end if;
117+
end loop;
118+
remove_read_data(l_buffer_rowids);
119+
else
120+
--nothing fetched from output, wait.
121+
dbms_lock.sleep(l_sleep_time);
122+
l_already_waited_sec := l_already_waited_sec + l_sleep_time;
123+
end if;
124+
125+
l_producer_started := (l_lock_status <> 0 or l_buffer_data.count > 0) or l_producer_started;
126+
l_producer_finished := (l_producer_started and l_lock_status = 0 and l_buffer_data.count = 0) or l_producer_finished;
127+
128+
l_finished :=
129+
self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec)
130+
or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec)
131+
or l_producer_finished
132+
or l_finished;
133+
134+
end loop;
135+
136+
self.remove_buffer_info();
137+
return;
88138
end;
89139

90140
end;

source/core/output_buffers/ut_output_clob_table_buffer.tps

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ create or replace type ut_output_clob_table_buffer under ut_output_buffer_base (
2020
overriding member procedure send_line(self in out nocopy ut_output_clob_table_buffer, a_text varchar2, a_item_type varchar2 := null),
2121
overriding member procedure send_lines(self in out nocopy ut_output_clob_table_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null),
2222
overriding member procedure send_clob(self in out nocopy ut_output_clob_table_buffer, a_text clob, a_item_type varchar2 := null),
23-
overriding member procedure get_data_from_buffer_table(
24-
self in ut_output_clob_table_buffer,
25-
a_last_read_message_id in out nocopy integer,
26-
a_buffer_data out nocopy ut_output_data_rows,
27-
a_buffer_rowids out nocopy ut_varchar2_rows,
28-
a_finished_flags out nocopy ut_integer_list
29-
),
30-
overriding member procedure remove_read_data(self in ut_output_clob_table_buffer, a_buffer_rowids ut_varchar2_rows)
23+
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
3124
) not final
3225
/

source/core/output_buffers/ut_output_table_buffer.tpb

Lines changed: 59 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,29 @@ create or replace type body ut_output_table_buffer is
8787
close l_data;
8888
end;
8989

90-
overriding member procedure get_data_from_buffer_table(
91-
self in ut_output_table_buffer,
90+
/* Important note.
91+
This function code is almost duplicated between two types for performance reasons.
92+
The pipe row clause is much faster on VARCHAR2 then it is on clob.
93+
That is the key reason for two implementations.
94+
*/
95+
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is
96+
lc_init_wait_sec constant number := coalesce(a_initial_timeout, 10 );
97+
l_buffer_texts ut_varchar2_rows;
98+
l_buffer_item_types ut_varchar2_rows;
99+
l_finished_flags ut_integer_list;
100+
l_last_read_message_id integer;
101+
l_already_waited_sec number(10,2) := 0;
102+
l_finished boolean := false;
103+
l_sleep_time number(2,1);
104+
l_lock_status integer;
105+
l_producer_started boolean := false;
106+
l_producer_finished boolean := false;
107+
108+
procedure get_data_from_buffer_table(
92109
a_last_read_message_id in out nocopy integer,
93-
a_buffer_data out nocopy ut_output_data_rows,
94-
a_buffer_rowids out nocopy ut_varchar2_rows,
95-
a_finished_flags out nocopy ut_integer_list
110+
a_buffer_texts out nocopy ut_varchar2_rows,
111+
a_buffer_item_types out nocopy ut_varchar2_rows,
112+
a_finished_flags out nocopy ut_integer_list
96113
) is
97114
lc_bulk_limit constant integer := 20000;
98115
pragma autonomous_transaction;
@@ -105,15 +122,47 @@ create or replace type body ut_output_table_buffer is
105122
and o.message_id <= a_last_read_message_id + lc_bulk_limit
106123
order by o.message_id
107124
) d
108-
returning ut_output_data_row(d.text, d.item_type), d.is_finished
109-
bulk collect into a_buffer_data, a_finished_flags;
125+
returning d.text, d.item_type, d.is_finished
126+
bulk collect into a_buffer_texts, a_buffer_item_types, a_finished_flags;
110127
a_last_read_message_id := a_last_read_message_id + a_finished_flags.count;
111128
commit;
112129
end;
113-
114-
overriding member procedure remove_read_data(self in ut_output_table_buffer, a_buffer_rowids ut_varchar2_rows) is
115130
begin
116-
null;
131+
while not l_finished loop
132+
133+
l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end;
134+
l_lock_status := self.get_lock_status();
135+
get_data_from_buffer_table( l_last_read_message_id, l_buffer_texts, l_buffer_item_types, l_finished_flags );
136+
137+
if l_buffer_texts.count > 0 then
138+
l_already_waited_sec := 0;
139+
for i in 1 .. l_buffer_texts.count loop
140+
if l_buffer_texts(i) is not null then
141+
pipe row( ut_output_data_row(l_buffer_texts(i), l_buffer_item_types(i)) );
142+
elsif l_finished_flags(i) = 1 then
143+
l_finished := true;
144+
exit;
145+
end if;
146+
end loop;
147+
else
148+
--nothing fetched from output, wait.
149+
dbms_lock.sleep(l_sleep_time);
150+
l_already_waited_sec := l_already_waited_sec + l_sleep_time;
151+
end if;
152+
153+
l_producer_started := (l_lock_status <> 0 or l_buffer_texts.count > 0) or l_producer_started;
154+
l_producer_finished := (l_producer_started and l_lock_status = 0 and l_buffer_texts.count = 0) or l_producer_finished;
155+
156+
l_finished :=
157+
self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec)
158+
or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec)
159+
or l_producer_finished
160+
or l_finished;
161+
162+
end loop;
163+
164+
self.remove_buffer_info();
165+
return;
117166
end;
118167

119168
end;

0 commit comments

Comments
 (0)