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

Skip to content

Commit 521fe47

Browse files
committed
Performance improvements in output buffer for reporters that only produce data after the whole run is finished.
1 parent 28b6eaa commit 521fe47

15 files changed

Lines changed: 214 additions & 10 deletions

source/api/ut.pkb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ create or replace package body ut is
278278
);
279279
if l_reporter is of (ut_output_reporter_base) then
280280
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
281+
g_result_lines := ut_varchar2_list();
281282
loop
282-
g_result_lines := ut_varchar2_list();
283283
pipe row( get_report_outputs( l_results ) );
284284
end loop;
285285
end if;
@@ -326,6 +326,7 @@ create or replace package body ut is
326326
);
327327
if l_reporter is of (ut_output_reporter_base) then
328328
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
329+
g_result_lines := ut_varchar2_list();
329330
loop
330331
pipe row( get_report_outputs( l_results ) );
331332
end loop;
@@ -374,6 +375,7 @@ create or replace package body ut is
374375
);
375376
if l_reporter is of (ut_output_reporter_base) then
376377
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
378+
g_result_lines := ut_varchar2_list();
377379
loop
378380
pipe row( get_report_outputs( l_results ) );
379381
end loop;
@@ -422,6 +424,7 @@ create or replace package body ut is
422424
);
423425
if l_reporter is of (ut_output_reporter_base) then
424426
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
427+
g_result_lines := ut_varchar2_list();
425428
loop
426429
pipe row( get_report_outputs( l_results ) );
427430
end loop;
@@ -470,6 +473,7 @@ create or replace package body ut is
470473
);
471474
if l_reporter is of (ut_output_reporter_base) then
472475
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
476+
g_result_lines := ut_varchar2_list();
473477
loop
474478
pipe row( get_report_outputs( l_results ) );
475479
end loop;
@@ -518,6 +522,7 @@ create or replace package body ut is
518522
);
519523
if l_reporter is of (ut_output_reporter_base) then
520524
l_results := treat(l_reporter as ut_output_reporter_base).get_lines_cursor();
525+
g_result_lines := ut_varchar2_list();
521526
loop
522527
pipe row( get_report_outputs( l_results ) );
523528
end loop;
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
create or replace type body ut_output_bulk_buffer is
2+
/*
3+
utPLSQL - Version 3
4+
Copyright 2016 - 2023 utPLSQL Project
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"):
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result is
20+
begin
21+
self.init(a_output_id, $$plsql_unit);
22+
return;
23+
end;
24+
25+
overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null) is
26+
pragma autonomous_transaction;
27+
begin
28+
if a_text is not null or a_item_type is not null then
29+
if length(a_text) > ut_utils.gc_max_storage_varchar2_len then
30+
self.send_lines(
31+
ut_utils.convert_collection(
32+
ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)
33+
),
34+
a_item_type
35+
);
36+
else
37+
self.last_write_message_id := self.last_write_message_id + 1;
38+
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
39+
values (self.output_id, self.last_write_message_id, a_text, a_item_type);
40+
end if;
41+
commit;
42+
end if;
43+
end;
44+
45+
overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null) is
46+
pragma autonomous_transaction;
47+
begin
48+
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
49+
select /*+ no_parallel */ self.output_id, self.last_write_message_id + rownum, t.column_value, a_item_type
50+
from table(a_text_list) t
51+
where t.column_value is not null or a_item_type is not null;
52+
self.last_write_message_id := self.last_write_message_id + SQL%rowcount;
53+
commit;
54+
end;
55+
56+
overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null) is
57+
pragma autonomous_transaction;
58+
begin
59+
if a_text is not null and a_text != empty_clob() or a_item_type is not null then
60+
if length(a_text) > ut_utils.gc_max_storage_varchar2_len then
61+
self.send_lines(
62+
ut_utils.convert_collection(
63+
ut_utils.clob_to_table(a_text, ut_utils.gc_max_storage_varchar2_len)
64+
),
65+
a_item_type
66+
);
67+
else
68+
self.last_write_message_id := self.last_write_message_id + 1;
69+
insert /*+ no_parallel */ into ut_output_buffer_tmp(output_id, message_id, text, item_type)
70+
values (self.output_id, self.last_write_message_id, a_text, a_item_type);
71+
end if;
72+
commit;
73+
end if;
74+
end;
75+
76+
overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null) is
77+
l_data sys_refcursor;
78+
l_text ut_varchar2_rows;
79+
l_item_type ut_varchar2_rows;
80+
begin
81+
l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec);
82+
loop
83+
fetch l_data bulk collect into l_text, l_item_type limit 10000;
84+
for idx in 1 .. l_text.count loop
85+
dbms_output.put_line(l_text(idx));
86+
end loop;
87+
exit when l_data%notfound;
88+
end loop;
89+
close l_data;
90+
end;
91+
92+
overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor is
93+
lc_init_wait_sec constant number := coalesce(a_initial_timeout, 30 );
94+
l_already_waited_sec number(10,2) := 0;
95+
l_sleep_time number(2,1);
96+
l_exists integer;
97+
l_finished boolean := false;
98+
l_data_produced boolean;
99+
l_producer_active boolean := false;
100+
l_producer_started boolean := false;
101+
l_producer_finished boolean := false;
102+
l_results sys_refcursor;
103+
begin
104+
105+
while not l_finished loop
106+
107+
if not l_data_produced then
108+
select /*+ no_parallel */ count(1) into l_exists
109+
from ut_output_buffer_tmp o
110+
where o.output_id = self.output_id and rownum = 1;
111+
l_data_produced := (l_exists = 1);
112+
end if;
113+
114+
l_sleep_time := case when l_already_waited_sec >= 1 then 0.5 else 0.1 end;
115+
l_producer_active := (self.get_lock_status() <> 0);
116+
l_producer_started := (l_producer_active or l_data_produced ) or l_producer_started;
117+
l_producer_finished := (l_producer_started and not l_producer_active) or l_producer_finished;
118+
119+
l_finished :=
120+
self.timeout_producer_not_finished(l_producer_finished, l_already_waited_sec, a_timeout_sec)
121+
or self.timeout_producer_not_started(l_producer_started, l_already_waited_sec, lc_init_wait_sec)
122+
or l_producer_finished;
123+
end loop;
124+
125+
open l_results for
126+
select /*+ no_parallel */ o.text, o.item_type
127+
from ut_output_buffer_tmp o
128+
where o.output_id = self.output_id
129+
and o.text is not null
130+
order by o.output_id, o.message_id;
131+
132+
return l_results;
133+
134+
end;
135+
136+
/* Important note.
137+
This function code is almost duplicated between two types for performance reasons.
138+
The pipe row clause is much faster on VARCHAR2 then it is on clob.
139+
That is the key reason for two implementations.
140+
*/
141+
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined is
142+
l_data sys_refcursor;
143+
l_text ut_varchar2_rows;
144+
l_item_type ut_varchar2_rows;
145+
begin
146+
l_data := self.get_lines_cursor(a_initial_timeout, a_timeout_sec);
147+
loop
148+
fetch l_data bulk collect into l_text, l_item_type limit 10000;
149+
for idx in 1 .. l_text.count loop
150+
pipe row( ut_output_data_row(l_text(idx), l_item_type(idx)) );
151+
end loop;
152+
exit when l_data%notfound;
153+
end loop;
154+
close l_data;
155+
return;
156+
self.remove_buffer_info();
157+
end;
158+
159+
end;
160+
/
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
create or replace type ut_output_bulk_buffer under ut_output_buffer_base (
2+
/*
3+
utPLSQL - Version 3
4+
Copyright 2016 - 2023 utPLSQL Project
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"):
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
*/
18+
19+
constructor function ut_output_bulk_buffer(self in out nocopy ut_output_bulk_buffer, a_output_id raw := null) return self as result,
20+
overriding member procedure send_line(self in out nocopy ut_output_bulk_buffer, a_text varchar2, a_item_type varchar2 := null),
21+
overriding member procedure send_lines(self in out nocopy ut_output_bulk_buffer, a_text_list ut_varchar2_rows, a_item_type varchar2 := null),
22+
overriding member procedure send_clob(self in out nocopy ut_output_bulk_buffer, a_text clob, a_item_type varchar2 := null),
23+
overriding member procedure lines_to_dbms_output(self in ut_output_bulk_buffer, a_initial_timeout number := null, a_timeout_sec number := null),
24+
overriding member function get_lines_cursor(a_initial_timeout number := null, a_timeout_sec number := null) return sys_refcursor,
25+
overriding member function get_lines(a_initial_timeout number := null, a_timeout_sec number := null) return ut_output_data_rows pipelined
26+
) not final
27+
/

source/core/ut_utils.pkb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,7 @@ create or replace package body ut_utils is
570570
end loop;
571571
exit when l_lines_data%notfound;
572572
end loop;
573+
close l_lines_data;
573574
execute immediate 'truncate table ut_dbms_output_cache';
574575
commit;
575576
end;

source/install.sql

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ create or replace context &&ut3_owner._info using &&ut3_owner..ut_session_contex
120120
@@install_component.sql 'core/output_buffers/ut_output_table_buffer.tpb'
121121
@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tps'
122122
@@install_component.sql 'core/output_buffers/ut_output_clob_table_buffer.tpb'
123+
@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tps'
124+
@@install_component.sql 'core/output_buffers/ut_output_bulk_buffer.tpb'
123125

124126
@@install_component.sql 'core/types/ut_output_reporter_base.tps'
125127

source/reporters/ut_coverage_cobertura_reporter.tpb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ create or replace type body ut_coverage_cobertura_reporter is
2020
self in out nocopy ut_coverage_cobertura_reporter
2121
) return self as result is
2222
begin
23-
self.init($$plsql_unit);
23+
self.init($$plsql_unit,ut_output_bulk_buffer());
2424
return;
2525
end;
2626

source/reporters/ut_coverage_html_reporter.tpb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ create or replace type body ut_coverage_html_reporter is
2222
a_html_report_assets_path varchar2 := null
2323
) return self as result is
2424
begin
25-
self.init($$plsql_unit);
25+
self.init($$plsql_unit,ut_output_bulk_buffer());
2626
self.project_name := a_project_name;
2727
assets_path := nvl(a_html_report_assets_path, ut_coverage_report_html_helper.get_default_html_assets_path());
2828
return;

source/reporters/ut_coverage_sonar_reporter.tpb

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ create or replace type body ut_coverage_sonar_reporter is
2020
self in out nocopy ut_coverage_sonar_reporter
2121
) return self as result is
2222
begin
23-
self.init($$plsql_unit);
23+
self.init($$plsql_unit,ut_output_bulk_buffer());
2424
return;
2525
end;
2626

@@ -84,6 +84,12 @@ create or replace type body ut_coverage_sonar_reporter is
8484
end;
8585

8686
begin
87+
-- execute immediate 'alter session set statistics_level=all';
88+
-- dbms_hprof.start_profiling(
89+
-- location => 'PLSHPROF_DIR'
90+
-- , filename => 'profiler_utPLSQL_run_on_'||$$plsql_unit||'_'||rawtohex(self.id)||'.txt'
91+
-- );
92+
--
8793
ut_coverage.coverage_stop();
8894

8995
self.print_text_lines(
@@ -92,6 +98,7 @@ create or replace type body ut_coverage_sonar_reporter is
9298
a_run
9399
)
94100
);
101+
-- dbms_hprof.stop_profiling;
95102
end;
96103

97104
overriding member function get_description return varchar2 as

source/reporters/ut_coveralls_reporter.tpb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ create or replace type body ut_coveralls_reporter is
2020
self in out nocopy ut_coveralls_reporter
2121
) return self as result is
2222
begin
23-
self.init($$plsql_unit);
23+
self.init($$plsql_unit,ut_output_bulk_buffer());
2424
return;
2525
end;
2626

source/reporters/ut_junit_reporter.tpb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ create or replace type body ut_junit_reporter is
1818

1919
constructor function ut_junit_reporter(self in out nocopy ut_junit_reporter) return self as result is
2020
begin
21-
self.init($$plsql_unit);
21+
self.init($$plsql_unit,ut_output_bulk_buffer());
2222
return;
2323
end;
2424

0 commit comments

Comments
 (0)