<div dir="ltr"><div>Hi Ishii-San</div><div><br></div><div>While rebasing the multiple parser patch after the PostgreSQL parser import commit, I was thinking of the ways</div><div>to minimize the maintenance overhead and merging overheads for the new minimal parser as suggested by you</div><div>upthread.</div><div><br></div><div>So in the newer attached version of the patch, instead of maintaining two separate gram files for standard and</div><div>minimal parsers I have changed the original gram.y file to gram_template.y and added a new make target in</div><div>src/parser/ Makefile <b><i>&#39;make generate_parsrers&#39;</i></b> to generate (gram_minimal.y and gram_standard.y) grammar files</div><div>for minimal and standard parsers.</div><div><br></div><div>Makefile uses the sunifdef (<a href="http://www.linuxcertif.com/man/1/sunifdef/">http://www.linuxcertif.com/man/1/sunifdef/</a>) utility to generate the grammar files from</div><div>gram_template.y file, So I have also made the appropriate changes to Pgpool-II configure so that sunifdef utility path</div><div>can be configured. After the patch, we can also give the explicit sunifdef patch to configure using the <i style=""><b>--with-sunifdef</b></i></div><div>switch if the utility is not present at the standard location.</div><div><br></div><div>The patch also contains the README file in src/parser/ directory which has all the information about what needs</div><div>to be done to generate the grammar files and about importing the PostgreSQL parser.</div><div><br></div><div>Also, note that sunifdef will only be required when we want to generate the grammar files, which would be only after</div><div>importing the new PostgreSQL parser or when we want to make some explicit grammar changes. And for the normal</div><div>build of Pgpool-II, we would not need sunifdef.</div><div><br></div><div><br></div><div>Thoughts and comments</div><div><br></div><div><div>P.S Sorry for the very huge patch because of autogenerated files.</div><div><br></div></div><div>Thanks</div><div>Best regards</div><div>Muhammad Usama</div><div><br></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, May 2, 2019 at 4:11 PM Tatsuo Ishii &lt;<a href="mailto:ishii@sraoss.co.jp">ishii@sraoss.co.jp</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Usama,<br>
<br>
&gt; Hi Ishii-San<br>
&gt; <br>
&gt; Thanks for the feedback, I have been exploring the options to generate two<br>
&gt; parsers from one gram.y file but unfortunately can&#39;t figure out any clean<br>
&gt; and easy way to<br>
&gt; do that. The problem is the bison assembler does not support the<br>
&gt; preprocessors<br>
&gt; off the shelf and I am not sure about how we can achieve that without<br>
&gt; preprocessor<br>
&gt; using the scripts.<br>
&gt; <br>
&gt; However, after analysing the end result of using one gram.y file for<br>
&gt; generating<br>
&gt; two parser I think it would be more hectic to maintain and especially merge<br>
&gt; the gram.y<br>
&gt; file in that case. Since adding the code in the existing gram.y file will<br>
&gt; increase the number<br>
&gt; of changes in our gram.y file from that of PostgreSQL, and effectively that<br>
&gt; mean at every<br>
&gt; PostgreSQL release we would require a bigger merging effort.<br>
&gt; <br>
&gt; And if we go down the path of having two gram files as in the original<br>
&gt; patch I shared,<br>
&gt; despite the downside of having another parser file to maintain, the<br>
&gt; approach has its own<br>
&gt; benefits as well. Like it would be easier to track down the errors and<br>
&gt; problems.<br>
&gt; <br>
&gt; Also the idea of having the minimal parser for master-slave mode is to<br>
&gt; speed up the queries by<br>
&gt; quickly analysing if we we need to parse the complete query or can we just<br>
&gt; do with the minimal<br>
&gt; information. Now my motivation of adding the minimal parser was that, in a<br>
&gt; perfect scenario we should<br>
&gt; only parse the read statements and short-circuit the parsing of almost all<br>
&gt; write queries. So although the<br>
&gt; patch does that short-circuiting only with INSERT statements, but for<br>
&gt; future it would be easier to make<br>
&gt; enhancements in the minimal parser if we go with 2 gram files approach.<br>
&gt; <br>
&gt; Another thing is since the minimal parser is based on the philosophy that<br>
&gt; only queries that can be load-balanced<br>
&gt; must be parsed completely and rest of the statements need to be routed to<br>
&gt; primary anyways, and can<br>
&gt; be consider as default write statements no matter the actual statement. So<br>
&gt; effectively we might<br>
&gt; not need to merge the minimal parser with PostgreSQL&#39;s parser in most of<br>
&gt; the cases and the minimal parser<br>
&gt; would not add too much maintenance overhead.<br>
<br>
But SET statement needs special treatment and needs full parser for<br>
it. See is_set_transaction_serializable (in<br>
src/context/pool_query_context.c) for an example. Same thing can be<br>
said to LOCK, SAVEPOINT, BEGIN (START TRANSACTION), and PREPARE.<br>
<br>
Also for DML, at least the target table info needs to be analyzed<br>
because in memory query cache needs the info.<br>
<br>
&gt; What are your thought and suggestions on this?<br>
<br>
If we go for two gram.y approach, probably we want to minimize the<br>
diff to create minimal parser from the full parser in order to save<br>
the work to create minimal parser, no?<br>
<br>
&gt; Thanks<br>
&gt; Best Regards<br>
&gt; Muhammad Usama<br>
&gt; <br>
&gt; <br>
&gt; to maintain<br>
&gt; <br>
&gt; <br>
&gt; <br>
&gt; <br>
&gt; On Fri, Mar 8, 2019 at 7:40 AM Tatsuo Ishii &lt;<a href="mailto:ishii@sraoss.co.jp" target="_blank">ishii@sraoss.co.jp</a>&gt; wrote:<br>
&gt; <br>
&gt;&gt; Hi Usama,<br>
&gt;&gt;<br>
&gt;&gt; Thank you for the new patch. The essential idea to have two parsers<br>
&gt;&gt; seems to be good. However, I have a concern of maintenance cost for<br>
&gt;&gt; those two distinct parsers. It seems the difference between two<br>
&gt;&gt; parsers are subtle. So why don&#39;t you have just 1 original parser file<br>
&gt;&gt; (gram.y) then generate the other automatically by using a script? Or<br>
&gt;&gt; you could have 1 gram.y file with some ifdef&#39;s to differentiate those<br>
&gt;&gt; two parsers. What do you think?<br>
&gt;&gt;<br>
&gt;&gt; Best regards,<br>
&gt;&gt; --<br>
&gt;&gt; Tatsuo Ishii<br>
&gt;&gt; SRA OSS, Inc. Japan<br>
&gt;&gt; English: <a href="http://www.sraoss.co.jp/index_en.php" rel="noreferrer" target="_blank">http://www.sraoss.co.jp/index_en.php</a><br>
&gt;&gt; Japanese:<a href="http://www.sraoss.co.jp" rel="noreferrer" target="_blank">http://www.sraoss.co.jp</a><br>
&gt;&gt;<br>
&gt;&gt; &gt; Hi Ishii-San<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Thanks for looking into the patch and your observation is correct, the<br>
&gt;&gt; &gt; patch I sent would break<br>
&gt;&gt; &gt; the timestamp overwriting functionality,<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; So here is another go at this, See the new attached patch, which uses two<br>
&gt;&gt; &gt; parsers,<br>
&gt;&gt; &gt; 1- src/parser/gram.y which is the standard parser brought in from PG code<br>
&gt;&gt; &gt; 2- src/parser/gram_minimal.y modified parser that short-circuits the<br>
&gt;&gt; INSERT<br>
&gt;&gt; &gt; and UPDATE statements<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; The idea here is when replication mode is enabled we use the standard<br>
&gt;&gt; &gt; parser and parse everything since<br>
&gt;&gt; &gt; we need the information in case of timestamp or other things. but when we<br>
&gt;&gt; &gt; are operating in the master-slave<br>
&gt;&gt; &gt; mode we don&#39;t need any extra information for WRITE queries, since we will<br>
&gt;&gt; &gt; always be sending them to the primary<br>
&gt;&gt; &gt; anyways, so the newly added minimal parser which short-circuits the<br>
&gt;&gt; INSERT<br>
&gt;&gt; &gt; and UPDATE queries<br>
&gt;&gt; &gt; (can also be extended to short-circuit all the write queries like CREATE<br>
&gt;&gt; &gt; and ALTER where ever we can)<br>
&gt;&gt; &gt; and try to enhance the write query performance of the Pgpool-II,<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; The parser selection is made in raw_parser() function and is controlled<br>
&gt;&gt; by<br>
&gt;&gt; &gt; the &quot;bool use_minimal&quot; argument<br>
&gt;&gt; &gt; and currently in the patch we always use the minimal parser whenever the<br>
&gt;&gt; &gt; replication mode is disabled in the<br>
&gt;&gt; &gt; pgpool.conf<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; This is the very radical change in the parsing function of Pgpool-II, but<br>
&gt;&gt; &gt; it can provide us with the platform to minimise<br>
&gt;&gt; &gt; the parsing overhead of Pgpool-II for master-slave mode.<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Your thoughts and comments..<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; Thanks<br>
&gt;&gt; &gt; Best Regards<br>
&gt;&gt; &gt; Muhammad Usama<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt; On Wed, Feb 27, 2019 at 3:58 AM Tatsuo Ishii &lt;<a href="mailto:ishii@sraoss.co.jp" target="_blank">ishii@sraoss.co.jp</a>&gt; wrote:<br>
&gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; Hi Usama,<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; I think this patch breaks replication mode because it throws away<br>
&gt;&gt; &gt;&gt; information needed for time stamp rewriting. What do you think?<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; Best regards,<br>
&gt;&gt; &gt;&gt; --<br>
&gt;&gt; &gt;&gt; Tatsuo Ishii<br>
&gt;&gt; &gt;&gt; SRA OSS, Inc. Japan<br>
&gt;&gt; &gt;&gt; English: <a href="http://www.sraoss.co.jp/index_en.php" rel="noreferrer" target="_blank">http://www.sraoss.co.jp/index_en.php</a><br>
&gt;&gt; &gt;&gt; Japanese:<a href="http://www.sraoss.co.jp" rel="noreferrer" target="_blank">http://www.sraoss.co.jp</a><br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt; &gt;&gt; &gt; Hi Ishii San<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Can you have a look at the attached patch which tries to extract some<br>
&gt;&gt; &gt;&gt; &gt; performance in the area of query parsing and query analysis for<br>
&gt;&gt; routing<br>
&gt;&gt; &gt;&gt; &gt; decisions. Most of the performance gains from the changes in the patch<br>
&gt;&gt; &gt;&gt; can<br>
&gt;&gt; &gt;&gt; &gt; be observed in large data INSERT statements.<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Patch contains the following changes<br>
&gt;&gt; &gt;&gt; &gt; ==========<br>
&gt;&gt; &gt;&gt; &gt; 1-- The idea here is since Pgpool-II only needs a very little<br>
&gt;&gt; information<br>
&gt;&gt; &gt;&gt; &gt; about the queries especially for the insert queries to decide where it<br>
&gt;&gt; &gt;&gt; &gt; needs to send the query,<br>
&gt;&gt; &gt;&gt; &gt; for example: For the INSERT queries we only need the type of query and<br>
&gt;&gt; &gt;&gt; the<br>
&gt;&gt; &gt;&gt; &gt; relation name.<br>
&gt;&gt; &gt;&gt; &gt; But since the parser we use in Pgpool-II is taken from PostgreSQL<br>
&gt;&gt; source<br>
&gt;&gt; &gt;&gt; &gt; which parses the complete query including the value lists ( which is<br>
&gt;&gt; not<br>
&gt;&gt; &gt;&gt; &gt; required by Pgpool).<br>
&gt;&gt; &gt;&gt; &gt; This parsing of value part seems very harmless in small statements<br>
&gt;&gt; but in<br>
&gt;&gt; &gt;&gt; &gt; case of INSERTs with lots of column values and large data in each<br>
&gt;&gt; value<br>
&gt;&gt; &gt;&gt; &gt; item, this becomes significant.<br>
&gt;&gt; &gt;&gt; &gt; So this patch adds a smaller bison grammar rule to short circuit the<br>
&gt;&gt; &gt;&gt; INSERT<br>
&gt;&gt; &gt;&gt; &gt; statement parsing when it gets the enough information required for<br>
&gt;&gt; &gt;&gt; &gt; Pgpool-II.<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; 2-- The patch also re-arranges some of the if statements in<br>
&gt;&gt; &gt;&gt; &gt; pool_where_to_send() function and tries to make sure the<br>
&gt;&gt; pattern_compare<br>
&gt;&gt; &gt;&gt; &gt; and pool_has_function_call calls should only be made when they are<br>
&gt;&gt; &gt;&gt; &gt; absolutely necessary.<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; 3--Another thing this patch does is, it tries to save the raw_parser()<br>
&gt;&gt; &gt;&gt; &gt; calls in case of un-recognised queries. Instead of invoking the<br>
&gt;&gt; parser of<br>
&gt;&gt; &gt;&gt; &gt; &quot;dummy read&quot; and &quot;dummy write&quot; queries in case of syntax error in<br>
&gt;&gt; &gt;&gt; original<br>
&gt;&gt; &gt;&gt; &gt; query, the patch adds the functions to get pre-built parse_trees for<br>
&gt;&gt; &gt;&gt; these<br>
&gt;&gt; &gt;&gt; &gt; dummy queries.<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; 4-- strlen() call is removed from scanner_init() function and is<br>
&gt;&gt; passed<br>
&gt;&gt; &gt;&gt; in<br>
&gt;&gt; &gt;&gt; &gt; as an argument to it, and the reason is we already have the query<br>
&gt;&gt; length<br>
&gt;&gt; &gt;&gt; in<br>
&gt;&gt; &gt;&gt; &gt; most cases before invoking the parser so why waste CPU cycles on it.<br>
&gt;&gt; &gt;&gt; Again<br>
&gt;&gt; &gt;&gt; &gt; this becomes significant in case of large query strings.<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Finally the patch tries to remove the unnecessary calls of<br>
&gt;&gt; &gt;&gt; &gt; pool_is_likely_select()<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; As mentioned above the area of improvements in this patch are mostly<br>
&gt;&gt; &gt;&gt; around<br>
&gt;&gt; &gt;&gt; &gt; writing queries and for the testing purpose I used a INSERT query with<br>
&gt;&gt; &gt;&gt; &gt; large binary insert data and I am getting a very huge performance<br>
&gt;&gt; gains<br>
&gt;&gt; &gt;&gt; &gt; with this patch<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; *Current Master Branch*<br>
&gt;&gt; &gt;&gt; &gt; ================<br>
&gt;&gt; &gt;&gt; &gt; usama=# \i sample.sql<br>
&gt;&gt; &gt;&gt; &gt;  id<br>
&gt;&gt; &gt;&gt; &gt; -----<br>
&gt;&gt; &gt;&gt; &gt;  104<br>
&gt;&gt; &gt;&gt; &gt; (1 row)<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; INSERT 0 1<br>
&gt;&gt; &gt;&gt; &gt; Time: *2059.807* ms (00:02.060)<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; *WITH PATCH*<br>
&gt;&gt; &gt;&gt; &gt; ===============<br>
&gt;&gt; &gt;&gt; &gt; usama=# \i sample.sql<br>
&gt;&gt; &gt;&gt; &gt;  id<br>
&gt;&gt; &gt;&gt; &gt; -----<br>
&gt;&gt; &gt;&gt; &gt;  102<br>
&gt;&gt; &gt;&gt; &gt; (1 row)<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; INSERT 0 1<br>
&gt;&gt; &gt;&gt; &gt; Time: *314.237* ms<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Performance gain* 655.50 %*<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Comments and suggestions?<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Please let me know if you also want the test data I used for the<br>
&gt;&gt; INSERT<br>
&gt;&gt; &gt;&gt; test<br>
&gt;&gt; &gt;&gt; &gt;<br>
&gt;&gt; &gt;&gt; &gt; Thanks<br>
&gt;&gt; &gt;&gt; &gt; Best regards<br>
&gt;&gt; &gt;&gt; &gt; Muhammad Usama<br>
&gt;&gt; &gt;&gt;<br>
&gt;&gt;<br>
</blockquote></div></div>