Making aggregate deserialization (and WAL receive) functions slightly faster

Started by David Rowleyalmost 3 years ago28 messages
#1David Rowley
dgrowleyml@gmail.com
4 attachment(s)

While working on 16fd03e95, I noticed that in each aggregate
deserialization function, in order to "receive" the bytea value that
is the serialized aggregate state, appendBinaryStringInfo is used to
append the bytes of the bytea value onto a temporary StringInfoData.
Using appendBinaryStringInfo seems a bit wasteful here. We could
really just fake up a StringInfoData and point directly to the bytes
of the bytea value.

The best way I could think of to do this was to invent
initStringInfoFromString() which initialises a StringInfoData and has
the ->data field point directly at the specified buffer. This will
mean that it would be unsafe to do any appendStringInfo* operations on
the resulting StringInfoData as enlargeStringInfo would try to
repalloc the data buffer, which might not even point to a palloc'd
string. I thought it might be fine just to mention that in the
comments for the function, but we could probably do a bit better and
set maxlen to something like -1 and Assert() we never see -1 in the
various append functions. I wasn't sure it was worth it, so didn't do
that.

I had a look around for other places that might be following the same
pattern. I only found range_recv() and XLogWalRcvProcessMsg(). I
didn't adjust the range_recv() one as I couldn't see how to do that
without casting away a const. I did adjust the XLogWalRcvProcessMsg()
one and got rid of a global variable in the process.

I've attached the benchmark results I got after testing how the
modification changed the performance of string_agg_deserialize().

I was hoping this would have a slightly more impressive performance
impact, especially for string_agg() and array_agg() as the aggregate
states of those can be large. However, in the test I ran, there's
only a very slight performance gain. I may just not have found the
best case, however.

David

Attachments:

string_agg_test.sh.txttext/plain; charset=US-ASCII; name=string_agg_test.sh.txtDownload
string_agg_single_group_bench.pngimage/png; name=string_agg_single_group_bench.pngDownload
�PNG


IHDRnAp'�sRGB���gAMA���a	pHYs�����e��IDATx^���$g��}n/n_..���"vc��e1{�{,wN, /�@ �$@B�@y!���B�{����^������h��O{�����g&''+�:�z�z��D�C����'�4������H�$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I���S���O>9t�A��3�o��v�7Gooo�����������/�N=���N?�����o�����6mZ8��3�~������
��^{-�u�Y��c�
O?�t���������d��z��7��g����)��^z���o�a��;��/�0u�Q��������|}}}��G
�&MJ����?><��S��6�u<���K�q�q��'�|���%�{����>:<��C#^������>X����kJggg���;�1�>���������%�\�<�������x��$e�J�V�?�|r�����6	�f��Q�M��F��'�H����?�y,����~8���������g�y&	f�����h���o�y��W���~;����o��s�����*	V����0g���oZ�0��w�
�_~y���\ p����^x���o�a�p��p�m�����wIx;k���o��+a*��8=��#�v4X��?��q�=�X��!���$�?������(�|k�7My��dy�/#-?�g��������_�{���6S��7��{����jdhh(�F^|��Iutt�#I��3��$�2&jpKp�M7�C9$p��O�SX�xq���gp�<�F�z��I�48e�upK t���&#�X?���`,�����w�$�!����Vi���H���''�I	H[=�t�VFp�K/�4�����Ho���e�]�,�[�������-������5]��7m���W_ZyxS�k������|�`�����J�4�n%I����2�����Nn��q4�m-�F��������x���c��O���
���b>���0��-!3�o4���
�510�y���\�E���
n	��}���w�~x����
?^�^��C�N+>����s�9'i'o�:r����y��V������8�g�}n%Im��V���0�]��vy���|�_}��[F�����y�"��"�YL9B@��f��)cz<7+�r������6'��}\S�5�t'�L���[o��������dy�o�9�����f���1��$�;�[I�*��v	����wpK�B0������ys������
�����\c9��e�-���c���s����K*YG�:Y�^K�(Z����)���?��s�z�Y�����K�1��$�;�[I�*��v	����wp�`��dd�M�����hp��������J��#�<2�R�vm*s�2��9^;;;��i���x���:.���������9k�"�fF��<s���i��V��L��F����$���J�J��Q���P�������I���������5sS�2������p��(��9�~>����k4�-�y��w�@����=���#>_�*�����X����SO=�B��K/�SO=5t�AI@@�)�T���xFe���Mp�����7�|sv�v�|�����s��-�NBGP����'7f�������>f{��u�����������I���!�rs�M�<����`:���?�/���/�_������y�-���4�
)�c�vx���S�#a�>B�+��r�o,gdm���+����&��z�";���A�WlO���
�</!���|�}\������g�������</�/�4?'$b>����������~c����G&�^��f�����>�C�x�-�/~N��������2C,����6q�����7�i�5���������O�������v��\//����w�'�9a}S|�Vz}�/Fi�>�v��&�#�$������������1�����*o$������a��U������88xcl�XG���v5Z#f�������;��n����f����f��������s���9�����/F���o���c�c�v�z�8f_k�o<m���c&���pm����a��/H�q\�y��s��	�	�~G[8�x�L�	�r�������e���|�z�kA��ez�6�x����s��q�~�����$����$i��Q!|����"�7����g�������N�$��F�r3F�o�b���M]�u5��|�S�<��Hge7���P0o}�rSJx�	����"x����lp�
97���7j7?�f�����<s=<���>#`���u�����n�(�!H��	*Y>��M��F���g������qzl|\^��������' &d�'q;��'`k�q���������K���
��wy�f�v~O�	T#�'�����IW����cy~���<w���/!������z��&��M~O�0�&�a�����y�!��B���H���@��q�����\����'�AA_����X���s����>%��;X7��/��b�<^g��>����]s�5��y�)��kmV��������R��B��2B���}^�?���5/����a]�e�5�_#h{�up�s��Z�vq��6��\g�����f�7���>L}I������@����K�Y&.�q�5;���W�a��y��}��8�iO�c�7px=�1���5�s��������
��y����Cx<Z�n^�����8w1��k}�$�5�D���$i,�J�F��B<n��7Q��e��b4X��/7O�Tl�=>]���:F����j&�e�&}m��b��h��aGQX�MAn�	,�3�e����w�����{����n	�b��]O�bhG3�q�"�7Em�w��e[	��Y��[B&��]��������e�:hg�4	>	�Ka
�k�Xo�����s�p4�<��8�}4�-�W�����B��c��'�#��vs�
���
n�{�<=bo���i�x��5���1Dj�r���GZ���3�����s�����5!\�hK�'�k�:�@�@��HY�^kx���
�"�YG�.���LSR�}�1�o�7R%���$<M���+���F��!�������+^K���-p=��P�^�,����5�����ykp+I�(n%I���AU�B���'7�7o����e(F���4��� �E����8�.�%B_��>p#��q��i�����/�|w�F��5��1b0>A$��}>���ie9��0�`���<0Z0�je�>C��M2�/��)�V���#yF
n���#�1��
L�c?�M���rs3������tp�77��X���~g�A��>`YBB���h/���7����)}s���.}� �r<���m���I[�BJn�	O���n�:y�.}�v�����>��)C�Ff�l��F��>f���,}?����V��v��x�q.n.���8R�e8wX���tp��������`���Mp��1��Q�i�?��t���i_��z��K�W��85���7�\zXve�\���s�c��q>���s���y�����ya5�����m����/n/��@.��y�-�#|K�������Y�^����[���M��Xh��c��0�������K�^8���r��m}��������y�;���]>+�������������N�M��/�����s�<�o�8F����c\9��nr
f�1R�c!�3�3e�iZ:�eY^'Y�Q����i�1���h#�U�������T(qY���obp�
��m�����x^F#s���^r���kJ�c��$Ic��V�4*�51%$H��Q���h��c��7A,��c��n��n��7J h�!7r��q#���iQp��qc����'7`����?3B��#,�8b}���J�<7����7z�r�b�����q#L��:���/'�=<���n����P��x���,>����N�:�N�G�Ch��(n�c`�?���h���9�}H��9��bH����v�v���'n����-E�,���s��m����n���1DX�2�yBxS��q��q�#������<���������[�#Db{9�}�=����
�8Z=�6��8����H���#�	o���W�F��������6�����!��`+�>��'��a\��5\c���p���Nv{��-��7/�e���ey�"��Q\�Pv}���s�����1O���6���c��W�Y��������:��iW��>�hr������sd��_���f5��d�������f��Q�<��N��~����h����y�
�;��x
���q�^.�Rl7�2�q�X`������eyJ/K��X|=�x�M�28��r2IR;3��$�
!Z+��&J���qc��X���	�F������7���rE��"8�f�5����gQp��"���&o��#Hb]|>n���"np��&Hn�sl/A7����MX��-��F���3�r��"�a�h7�	ob? �r��<�1�%PH�Q�"��e��'�=D��V�lG���)A2���������b�Z�m!��a,��n��<���g]����LpK����6��X���$x���!
���'b������x��Q�y���6�))X��ny���~<�?�]^�"B.���y#�kP�~q^p������4�^�5�|��Y6�e}�/��c�+��F�#��O�/��N�������`9^��D��=�S�?��q�����u�]���9�8Vay���<�h��EF��Z�&��I��7�x���9����_�����{����vqMI_���m���.�SqY�E�2��i��\X��0ov�9^x���$���J�F��"�qF���(�f"p��M:7�EpD�A��
aS6�,
n	Ahk|>nx�y>�#�%����1� �!�G)D���EX������� �e��f���0�~�����~��m���)F���|v���(f�D�S�An�c�����}��	E���9FN�|��hAmc}lw���o����kF�N4
M��6��x��������������	��}���������]S�����e���X���L�/�s���j�(����-�
�=����5��z��r|�i��m:e_p�i}�	�^_6���'�#�7f>�_�N���7�?��o��q������@��5��J�	�GZ��������y8F�>���q����.����C6lM��V2Z������7$X��q
l�,�/���^F��J�VE���Q�&��@n��a�F���']Fs2}7sE�`z��
%�(*n�������e?�^�2"*���#��{�te��m�c� ��7�����G9Gke���we���)���[�)�^Q_���H������$"���V���E���������q$�d�|��x�t����c������G3��h�[���������l�[�����������;��`e�78���J+#�	����_AM�q.��lpK���c~�1E�����w�\���3q}��i}\�����6����s�`�J����y��f4:o����h�-��y���",�7�
s��1���78]�,��d����q,�7�h�3Q:��Z��)��2�r�0�q����E�Y��)�[I����V�4*�D�� /��H2n�"@"���|q���Y���->�������6=��l1(~�������s���5ke��Q�e�����H�����!E^pK��*��DF���i�t�_q�e��[�� ��Z+�|�����E�-hAD��E�@���$!��Q0:�����~l4�	ni#Aj���6���#S�8'��1+;�����_���Z����3���Q��6��
�.����OcX�
n9'c�1�����q^p������G�r\�ys������t�L���O2p]����\g�p��f�FF�����0�?.�>�m�bl�m���n�V��j$����J�>,n%I��n�}������	"�$@ �H�T��A�lq��lp�
h+�[����`i"�|��mzN�V�����^Esh�c�����-��HaW��[����,�~�M��8�m&�������c�G�G�f�U���������#�%�$�d���*/��o����H�Ak6�M���#���8��kEp��D(F����5#��-���\F���i
I�#��i�p6��M�w#����$���V�T
!s�q�D@�\x�������������Xn�0GS<�c�����Yy�,����
�-7��m���c��>V�m��5mU
n#��L�G������d�����Y��[���G���[B�x�k9���LY�9M{����6��{p��DH�u7�8�	yN�s��y�����L��6��,�[I�Vdp+I����P�P��{B#F�r��\n����f���|6���YE�-!D��� ��*��
rZ�%I���A�������G����j��*���/Qb�
~��f�q\<6z�Dn#�}�62W*�����n���V�yz?N��6�\���6}��upK_�}�=�8�o��0�/B�:�y��G����t���|6�e��s���t^2�G<���-�;=���������E�1i�	ny.���b��	h9O���zX?����Dn��E�Ld�|:$��PF��[���.�,Yv��p#^��V�_W����J�T���$���a'��f��0�8Z�"n"�G�c��
"7���=�YE�-AP9�A�F���1���}�����t��
+��&�Qx��ce���}��v0��(�kF��[���t���<�=��s��c�)�e
�:�<��#��r��p�ql0�/>7!#����Dn��]�����E}����<f��[�)�d��8�8�	�������lpK`����
g���8���)��tpK�Cb�G[GZo����
y���,/�A��
y�9_,��p��P�k��Q��C���r����/��C_��6���mC�g\+	�G���k�"�'o�.���1��$��[IR��������1(�(;A\zdm���P���P��=n�����!������:���MeQp;w��p�,}>Bn���eC������rSK�����o�\�7�����#���X��-a�N�B���O�X�GH�M?���OB��U�-���	o�N_��,O�Sp�1�~��F_���/	 ���>����~�x�1�d�~���-�?���0�m-�>���,���:�������h#m�8k$�����9�b��q�����2����k
�S�<�������`�k_|�,�G�a��e�[����ur����������8���6:�A���OE����(n'�QI������������/����kHa���Z���|Q(�'ya���$I��J��������,�-�nD�q���+���.�j<�`�p��qsO���Xn���#4fy�K0�������#t�#�x>n����^�5-�����|�Ez�Xn�N�l7���?�yN�6++��hg��<��Q���������������-}A F8��2:;o�^�'2�MT;����cdy���f�����xJ���$�K��=�e	x�t$�������(�3�R+#�����8�x#��b[��O��>����Q�w����;�h��\������/=��#(������������-�G��p�Q���������!��oTeq�r
�������0�]p�vr�r<�&d���<���<oJ-_���-�
��x����5
�y��u��.���������V��jn%I�B�D�
EhDhBX�#n���#��f��qn��YMC��q��7n��B������?����/7����%4��`E�-x>�M?���d��xm'�����l0��s�I8�r���s��zX�0R� ����c����cpK��=#��7��Q���Rn�	
b?�O�y%����>dT�N���
`Z����P��$���u\��:X&nC���[������o��[�����nk#��34����}D�h+�N`HH�~�8f�������tpK��c�#��9����.�_\C�������g��eX5��-}�(g�o<����m�/y��`�k�rl_6�E�����m�z�c������d���j\_6�EO��#@��9�Y�#�x����-	���F�:�C��v�,���2nK\�k�/���"�qt1��!}^t�<!z\���h�"�nA���c����q���ZD{�6�z_���q�uy"����&��hJI�V6�[I��p3C`?��>�
�7>7Q��s#�����>YWbh��������bHE5
6G
ny>�~C���|���:	8�7r<���h'����_b���	Dhg��s#��q�?�F�62RpK�	����h�!��~hep�F3�exn��t�����X���$;R��e�fE�>b]�Vqt�X��&l#�@������ �c;b;��$o���!������aI���YlC����c��/nol+�B�c����v����yE��s���>������e9��"����*no�zR�����������v���<�;�y��7�X�'�r�zq������>w3����
��l�J��hG��'�upd�g4Y��x�M�"���		GZ��X�7�G|������`�Mq��_^O8'x|Z��\;9����me����M�8�����;�bT|���$i4n%I��H)F�q�o�7{���R�:p��(,F�p��#7����ya�H�-x7��i���Q�|�De�����F=��~�K�9�#�?�EX�n�H�-h7��Fj7E?��oy�������q���� �}�6p�4�b��>~)[����Ep��5�d�x�Q��Q�i1���\�x��	?��'B
B��z�R,�� o������ ��y�q�:���t�2V�C�1������	=�7?���=������h{�N�7N����1���8.Y_��*�/�oyA08>8/	����6o:p�����Fz����ZG��3���9���~��l�h�������up��v��6r���x��h.f�g
�����e�Ep�E\��H��������q���vn�����vQ��G��m���<'���W��V2��$�Bh�G���0a71����a>��M[��w#�q��
-�7�1d�������r��ry7�h&��'P#��f��#�|������F�e��n?7��*��bj��/��b����oco��4�"���%Pb���w����!'�(���n�M8!7���>% d�M�������;�@(�U����"���'�c}<'��H��8��>!8��+���<7�J����%�bD}�����!7�
!�}BH��f9��c�&����c��%�oe���%l"����������/��f������d��l/�&�=�k�q�\����F���]��q}<W\���Z�k���g�n4
nik���c�7�8>9�9�8��D<7���������c���~vDo��\?�����g�v��F��s�T�9V�-��\'�/>�9�o�\�8y���5~"�c������@��]q�[I�x0��$���7J��6������I�t���|���u�����
37�<����|���b����?����m��}�h��z����i���#=~��G_��i���Q\���������0�P�6���N��;V�A`OK�A�F������O�����x~�������x�����F��C�F�}V�,��yh��\l/�������
#L	�V���q[�m���~M��o�G�l/_f���T��s��7���x#��*�1�x�p�@������Ol#��wi<�'d�M�2�m\����4�B>B���,H/Oh]���f������t$�����k|3m�XW�&��V����e�wq}�+nc�
lK�g�c��V��2�J�����A>"��s������#���b#�	�����@�hGFj0�y��I(��GA�>e�)s�4B��*1Z�c���l7C��2*�5�1Nx��D��00���|��Y\#&GZ�N\af�K#�GB^BO��k��6�_+�S��
l�h��[�����Q�#!����f�%�5����<�_�Y���!8������)��$�*�[I��6��t�X-!'7����:>JK0��<n�i��n����$�bd^���]��	��/F'��8q~�(QBGB1��F#��A>�|0���tE_����|���e��^�������&�\�7A]��������:Y�s�����
�V��g
FW��eF<��j�A?�9Vxc�i&�n�s��U�\����iy��x���<$Ik��$�mn0�1�
81��9l�xIK�Bp�H9��d9>>��2G��Fz��sa����ct"sK�P�����o�'�$��O����o���2,;RH���^�-�_6���1�mz{������7,�;7����Q�q.i�e9�#o}�����Q[���>&�$�%�,3j��ffz��fkQ;a���qSf�/s83�2��y���R#,�),���#��	�A��
��IJ�4�n%IR� LJ��,�a'!�����������Q�L�@�[&�YYj��?#Bu;2��#��_��KH���dTi\�����1D#�dtS��T-���x���/�+�^����2��{��GrC@����YAo����0"�9�Y��u��X}��
�2a1� �fe�y`	�8�
#�S�X-�y2��3��/c�����(�
�T�����$��n%IR[!4�c&�%PjT!LA�Q��3n�	l��w�H�911�|�O�x�[�s����q�LF��CG����q4i+�Q��>�l�Z���8&�mf{	K���c�q}W\qES����x�d4��@���v��c�)4����d�,�U&(f���%��:xS����g0b����^�>~�����Z�|�����{�)|���$ie1��$Im��L3��;��3���1�%��#���
�D	Bh'������8|�Z��/>��G�	�aCXF�2���s�I��d���������x�K���������S�Xi�_\_�G������>�+���]���� d�o��F����B�|�Q������eB[T]G��)�s����g���iy�/���fF�K��*��$�-��d�y����r��^�&�Z��6����}������}HFX���3�~L��
cN�h{9mo#�^_�����!���~��G�$����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+IR�C�������=��gtW�_]���:�z��� ��?��.:;���ga�v�W���(��o�������K�$Ic��V��&���`��������a�I����\[��o
��a���7/���a��iapp������|�g�}�SO=��c4�-\�0<��#��^X%�w��W��M���^=�^k���������6���b���!����{�7�|3t�A�W��Ux����?U��?~x������>[������k�5z�=�o��v��+�����>����v����{��SI��J��$5��G��f'u����e��q]��W��0��������9�=�XS����������?�����8���:+�����O�SX9����/8sI����[Vsw�&�=�P�I�VGGG8��c�s����{N����/��z�0e���O���.�y���������?��^z)l���a���
o��F��+A��������%��$Ij=�[I��p�#�a�[�~�����J
n?�������.��g�^3!,�0J������jU5g��p�1�����g��;�\5�����
_���_�4�=�@�I����3�`l��7>�`�������s�������S�#��G�]w�p�w�::��$��n%Ij��1���a�����������/��?h:���Ap;y����:��J��\��$5�]���n�!�x��k�����&7�������2<�@rS�O��O�3��L�����{��#��e�t�_~y�����;�6�d�p����W^ye�9nY��a�r�)������~z�|���Zk�v�m�p�}������y#�'�|2r�!a���O����K�9���������\�����_O>r�v�����x����===�%�N��b�-��a��I��g�	_|q2W$!Jz�"��}����?�q�����l?�����~{��F>}�i�%}@_������7a�
6H�T�jf^��Ix���{�!�nF��|������uX{�����$��UW]�Lq��h��d{X��h���K���{�I~��;���_�%9F����-���?�|�{2]{�����Er���G?
����(�F���_�����N=����{���Z	�8�%����K���n��������#�L�	F����l�M�����O}�S�y���{&�%S ��]tQ������;������sNr|�&
��e�y�����9�8��������|�;��)�zq�qN�8��-��29?���~�r�r]���O~����o~3969o}��F���Q=����Fm���\pA�������k`z`���M/�u�����?�]v�%L�:��t�W_}5Y��NH�����h'?g?d����g���O��d�8��.s��],C����N������?��?$��1No144�y��d�p�1�m�5kVrC:�����Skp
����<�7j�����
\��.�Q���^��=�������'��O<ap+I�3��$�	���(|�������������������g������'�������,-n�	-10a�' �����;���F=;�-��!����>>��O&�Mx^��B�r�-���?��?&�c��~��I`�����p4X?���f�%�#���'>�\?6� � � ����?�,���c?����P�`������	@���-�n��_s�5��I��D������~#t������� � ����C(B���}��7��������6�������I�E���%@�������e)�M�K��1��}�>F�	f@K@�����K��u����}:���@�Kx�B��6�.�U����M�����'�*A,�9���A���w�6�p���	}M��yK�O�N��>��W������9n9o�������[��I���A �9�>oyS�k�<�[��e�laj���=����7!��.��Q��?�����a��wO��5 ~�����y�����;���7�>��9�>���z����x^���|f�����E�{�e�%�#�\c_��/op�o���s��������u�
��p@x������������$�f�������/��s�������zC���g���r��s���6�J�4vn%IjB;����m���{��I �
��W_�����mEHK��7#:��
9!a��?c��$�cT`���xEF}���;��C������������\B=B@F
J0T	nyn�F,63���<'�|r���,�nF�d�N����q�~�_H�����n,O�L?�<�Z\��5�~�K_JB�s�=7ic9�:�	��	�	B�9�HJF���o����J�!�a�+�/�A
�a�a��W��e�$sl�0��u�1�o�g�������4���X���M��>���.�$B.���I�	}�1���ap����M�}I����Q�O�[��F��1FS���}����'��O��W��������e(��s��s����jI�G[�x���L�}�a�s�m ���r
���v�\`�#C<!$�O��O�)�7~�yMX�:A9�	�cp��a{X���NZ�<�k\������&���X�;����9K����u������x=b�*��D�=���T���-S��s��c�K<�8��^q�3���1�e��	�i#��/��M2��\S�y�(g��c��x�?'\�����Z�����-���j����$��[I�����-#M	!�����&�#t%,�#��qK�:��9�&YxL�����p�p���!���&�`��'l!�b�B@~�k_+����v�9�>���c�q��%4a���3��m%"|��K?1��������<a(!Gzy>�L_�|��-�N�/(��X��0����[	E�w<�����0���Q�,O�N�J{�hE�H�B��)`Y����A �q�vZ3b�07;�����Q@P�yN�B}��z�+��Z��0������$t�#�q$x�K�q:�n4�-�-�)��8.O���,��%\7h��8��,�yK;(9&O<����},����lp���qA��%ls<6x�H�q�k���}�,�q�q�CPM��9�[��Xdy�����)�����LS�:���o�Lo��������������Ko�.op����r]��q�yw���'�����4������E��[�_�{���������1C;8&8�8������w�1�'5X7����k�����?�%�����n%I;��$5�]G�0��|�+d�7�Y#��J�~�
7���[>.GpE0|��p���P�y �;��)�����ue�[R�m��������I8��;F}0�3��Qb�f�n�1if��Z��+b01z.�<!��7���1��Ri��w{@��>f�� �~��v�@p�(N��`�����{"�[FB�W\qE��cX���R�����������#��bnN�KhL0�[�'��m<���d4(#�	���bY#���G�GE�-�b}�q|�{B\�'�G�s������9W�&�
nYG�yK�G�c>�y���L/B0�=�O�:����0�������9>��f�[BL�3�������/�7�l����o��pFs�.F�"/�%���0|2!{]��\�y8?cpKP�(�4�a��\�9�9���y�3�L�Kh����&#{y<�/���O����V���cp+IR�1�et3&�c.C��������0h�����2z+���F�-7�|t7����"�!���z��//�������}1�#�`�	���|��9	D`	2	Zu�F����	�n	_xY>�&Mcy>r��������i1�%"tK�����������R3O%��2G*�O��LKA(F�LXK��G��B1B���Q���n�f�#FF����}�Hb�����[��6n	�����'�c�T���2�o D#�3q>��(�e$+o���|,���� �����f��M�'��y���������y�-a!#X�����,��E{	Ecp�u��������f�[����kh�
��)����]��e$1�#�qv�M��y�-�������V��"1�ed�|��>����>f�\���6�<�����n�Xa�2�l��h?�7��$i��J���vn��'�}����P�y0	�s�����`�0���-�H������6#�f� ��x���m=G�D8�|����/��o���������&���Ak:�%�%�L����������f������&�e>�M��1��i'[	���r�J�P2�%a!_r��;���6/�e� �'�:��S�P��$[|�=Aq�
n���%	Ly�������8*v,����1������f�v��E�yY5���-�(o6���- ���d�6��a�Y�l��c������1n6�e]\�����<���:�'8?�6�]L'��XL���'��g;����y�-?�1,V$�������k o�p�g�_�e��L[�&pl0r8��8���$�
�[I�����mD����|���:3����Q�qJ��ni!7�qdgDh�4e�[F�*��j�BB�
������8����f�H&� �L#� �$ "���	\h#S�-�)���
n	G�/��mb���6B]�i��F#���n�||����������mb�1�A�1������u�!��X�"2~?�-�-��y��BY�SF�
n�����	(9O�y�9MI�cp�1�����,���9�l�-����c��lp�9K��4��A��8�6�3�������1��H�-��E�����<EF��d��9\������7���8vn%I;��$5����4�UF����xn�	�#�%`t(AA
�M��1����0%�e.���������'�1ha{��{��ODxJ�BpK�Dp���?y����n	��(=
a
����c
�<��i�
�O�C)��
n	j�3��0�`,������������vt�c���g�4o����������^�\O"�d��%�+�r�`���Ei���s����1��:��Q��~I����v�u�����:L%�]���7�r=c��y:��M�e*������3�qz����?�=#�q���`�����MF%��&��\�Y7o��F_z�8�h��y��7�z�K�N���������V���cp+IR�-�����G���4a�_TE8��J��r�N8C��ni#��������[����{��~����[��(E�G������WL�[�G��~�~�����|T�)��,O��|���g������������;��#�4���>��)	nyNB*�eB���u�	'$�K�7�1��H`�������A�.~�(_B<0F1"�n�����3�����h��8W�7>������Yn9�	(Yc�r�p��x�������[C�c)����'s�*2R��"p��e�L�[���d��7�x���BZ����<�Hs��<�c\��b�,�7�r,3�����|c�1�86����9D�N0��!}=�<�a����5�\3�.�'Het.�
����������|j�c�p�9hG��vv�a�\��|f�h'�����)�8����v���uS\[����V���cp+IR�-����j�n���*>�N��/|�IK��7�����+�'�����	��M�����%�V��P��
�'>����-�E�I��/��/K�����IX?A	#�mb[9����D����������%������	����_YS%0�����c����-_N���.>���`�T�-����c�>"�a�}Ip�������hm���
�s|������w�@'��5�m�0�s�`�yP9�>�M����������>g�3�+!�X��z�h[�-�}����X_���>`�)#���������s������3���f����	V��A���
n9gy����uP�7����$��
���_����y��b��]����_�,�9�<���l;�m"d&��Z�\�q]�y�V�}9�����`�7���3s.@s�F�-������F�s�[I�����$IMh����G1��dt)��(	�Xs�7��H@hA ���X�������������Ui+��N����	09F��H:F�2_P��2�&��B�/P��8J��h'AG\��f�-���'`���u�]K������>�����P��%l�?�F���w���������F�D��hG�B�8��c�Pp�}�I�.���eX��e$$��M�%�>��6�-���9�O��`���u��8��=�r�p�r�rn��ep��dd%�i<o)�3�`]�����Y���������yK0
5^�-K{���Q�</���������-~�[��Vj�<!q\�������;���8�8�97Y	9�Amz*�-�JF���%�\3�^2]s�r=:����`���9�v���O�K�9�E����FH�u�7U�&�sU�6��3�&�������
or��g�F+�:�@��\?Y���J�4vn%IjB��q��?#%	_��,�+���@7�����p�O�o~�
y<�
�,�����	"c(�-���Q��1�$��I��v���������<�(��L�	C"�N8AHF��c:�H��f�g��gaz�,��6�������B�'�>ex.�O����}������\��}�z��<G<Fx,����x���,C`��������b{�!�����0.�x�[�9���������}�[������1�=oY7?������g�������y���xF����E\m�yE�=o1K{��m��0b������+j�<��i;axz�<1��
��>�v������v�,���.�%q�������W�?�����������a�f���e��z��x6:�#���eY/��cX��$I�gp+IR&�������/�8������' 0�����3���'VF����?qD*m"Pa�IF����x,�<��zcts\���9�i?�Q��C����
�6��2/�/�b<o	u��m������F{�����=|�X�=\G��Hd���=�I�k5Z��SNI�g�8@#����W�$ie3��$�	��GP�����=����|l�b�F���s�2�k�}�]��f��
x�h���Q�8�+�b�F�`�\>�G���k��F���M|�������m)������y�-��U�[�K�M���f��HF�6���%e��L����i�� �e�{��w���y�3b�)
X����$Io��$5��u���s�������w������pL#�7�3?#sY1G&��~Z�/����=�a�h��d�,s�2��`�/������9n�;�6�@'.���&��H�����~S���F�l���o��k���a����HT�aW����eNY�QM������y�g��a�����A{����x��:���#��|���=�dvy��ea����^��[I�4�n%IjBO����a���a�+{*�Q7��g���Uw��R�������H�Ch����+�y�����"Hi&|�b$p����i#��!o}�]^�cx��$�]�������\�N:*�?�d^��;�m��-�a����Xo���5R{�X>�K����E����#���H�$�l��$5��v^�p���z��~sil
����04wN��Y�������k�$I�P1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��f�������[o
���K�={v��Y��������o�������o|#p�a���app���2,��3�����k�����x��r��$I�$I�$��[Y��u�Y'����+���������/�����?���������3������CCC���,�w�/����?��C���$I�$I���#��<�HXo���G?�����k��o��V��w�>������;.<�����GqD���6�,����K��n�a��c�=v��Gyd���������3f��<�$I�$I��a���O>9|��_���������4n�;�����},L�<9��3'�=#l�������.���000�,���'#m'M�:;;�[����/�����K�$I�$I���#b��v�d~���Z+����+�===����u������SO-7%���s��\�g�}��������s�$~��'s������{��h���O%I�$I�$I���W^�y��0k�����}/7�e���~����F�������l6�x���,��&�$����{��3����9s��K�$I�$I���G����0�A����7�_�������0o���O�a���;��_�$�e�����H�8�B����N������$I�$I���G��-n�M�V[m���;��������n���|�����^}����������>7�e��w���V�$I�$I�r�,�%�Mp��{�J�$I�$IR����������]w�u��-S,�>��,��,��,��,����\��3_S�-_&F����������V��/#�������ee,�����t�MG��d,S�N
S�L�,��,��,��,��,�����/����z��������������^����W^y%|�K_
;��s�.Z�(���o;���k����_N������m|�eY�eY�eY�eY�eY�D,2���CCC���N
������_��0^����+����#�|�����/Y���_�E�����k�_y����Xgooo�7#L���,��,��,��,��,k"Wv�kVS�-�y�����}.|�+_	w�uW���~��a�5�HF�>��sIh�����,��w.��7���d�g�}v���$I�$I��%�n{zz����>��O�/~��I}�S�
���'�\�|�X������������?�����U_Z�$I�$I�5��e\�Zk���������w���d���s�������k��ty������$I�$I��Tp��
|���i�
'�����x��d��F�>}z2r�Q��<_vfh+I�$I�$I����$I�$I���`p+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6cp+I�$I�$Im��V�$I�$I�����$I�$I�$��[I�$I�$Ij3��$I�$I��fn%I�$I�$���J�$I�$IR�1��$I�$I��6��ng/�??���/����p�=}��g�{s���p}!I�$I�$IG����9C���{�ON�?8�+ltlW�~��<�;�uIOx���04T_X�$I�$I����*�=�����Q��w_����8�p[o��w��$I�$I�����
n�?�;�5)?��6;�+,�1��$I�$I�4�>T�����
lc���6��$I�$I�4�>T�-�������ep+I�$I�$i|�f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f*7�o���}2�?�D���0�pA�sI�$I�$Ij5��Le������E����s��������i�������~z�/����$I�$I���0���r���pXx���c�o��k�f����j�?NF�����$I�$I�$�:��L��[B��M��
mcu_}i���?B�$I�$I��3��T:��������o���}X�Z\�$I�$I�$Ugp�����;o
�Gn`k�����E���$I�$I���n35��v��?	��!I�$I�$I��fj��m��
C���!I�$I�$I�5���93x��a�-�?�����{��z��0<�$��:uj���~��,5e��044�,�2�Ep�������9�GH�$I�$IRuM���M���Z��?�����|�a�������^Z�^x�����h���w��eW��n��j���$I�$I��RM�.��~{���K�%�\�\�w�ya������=��0���1������
�������.�������/��2�Ep���������GH�$I�$IRu���%t}����>����6�,7M��y��N�0k����6bp+I�$I�$i"���n��v�����������	a�������f27nwww�����V�$I�$I�DP:�e���??|�S�
�'ON�SH{��G�_��_��O>9\�����N�4)<������+���$I�$I����tp;c������o����^X��dQ�b2����_�b���?���/I���o}+\}���������ap+I�$I�$i"(����d�w�;�����U�����>����M6�$�t�I���.J�����/|�3�	���zx�����`�Qc��V�$I�$I�DP*��={v�l������������0��0����
W]uU�2eJ���d���3�	'�>��O�8 ,Z��������U����k�����/�����y�z��]�y,��,��,��,��,���j��������?	^��k�Q�_\������7�8	r	t��s�������^+U�;zanX��g���t��.:7|����m�w�ux��)�=�eY�eY�eY�eY�eYV�"�d��"�n�R�c�9&����m���KMu�x�����;���[/���;M�,��M���j�j&�}z�kK��~�9#���:L{������,��,��,��,��,�Q�q�<��3gN�b�-�Zk��|���C���������:l����w�mzl�o�����am���X�����
~37��5���E�g/�<�eY�eY�eY�eY�eYE��~6k����/����/�]w���4	���a��I�������[!�}����������v�)������I�$I�$I�F��~�����x�c���2�v�v������g��|��-�?���a�-�������W^9���V2��$I�$I�4�:�=����������������������W���dd-_B���k��F��������F��d�`p+I�$I�$i"up{��G&_L����������������'�����������W�N�<9��w�yZ��V�$I�$I�D0��v�����nH��i����@x�������/�\sM�6���`p+I�$I�$i"up;��J�$I�$I�n3ep+I�$I�$i��f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f��V�$I�$I�x3��T;�����a�����{8/k�$I�$I��U��m��!�}g�P����0���p����w���������f�
C��$I�$I�*��6S��v�
��n�
������|���)w����&��$I�$I����6S��>��`������6Ly{0� I�$I�$i�cp���n/z�/|�����������_�$I�$I��U��m��;�=�������m�u�#����V�$I�$IZe�fj����]��="�m�n%I�$I��U��m��;�����������2��$I�$I�Vm�������u�5'��-���$I�$I��j3���S%H�$I�$Io������?��
��o[,�[I�$I�$i�fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io�����������������C�e����/�w�g�[��P})I�$I�$I��m�&bp;8������a�N[��M��?\'t�h�0g����C�	�^�-4X_Z�$I�$IR�3���Dn���(tl�����^k����c���E��%I�$I�$�;��LM��v�����|%�}��-7
C���%I�$I�$�;��LM��v����m��Z{�0������$I�$I����m�&bp���ws����f���$I�$I���n3ep+I�$I�$i��f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f��V�$I�$I�x3�����$I�$I���fp�)�[I�$I�$I���6S��$I�$I����m�n%I�$I�$�7��L�J�$I�$Io��2��$I�$I�4�n3ep+I�$I�$i��f��v���vxij�qJx��0�ha���[�$I�$I���2�m����	]�_�o����a�^����#,<������p_o}II�$I�$I0����m�->������a�Z����y�n����`}iI�$I�$I��2�m-�G���&��m��+/��aW��$I�$I�n3ep�Z}?�d�mN�b-<��04n��$I�$I�n3ep�Z���:�Nn�b1��PgG��$I�$I�n3ep�Z��sw�:��U�$I�$I�$��L��V3�m������!I�$I�$��6S���Lp;o��������$I�$I�dp�)���j&�]������9�GH�$I�$I2����mk�J�$I�$I�gp�)���2��$I�$I�F��6S��ep+I�$I�$���m�n[��V�$I�$I=��L�����$I�$I�4z��2�m-�[I�$I�$i�n3ep���Z7�Y4f/���"��V�$I�$I=��L���������Q7���7.�����:z���J�$I�$I�gp�)��b/�7���g�6�5yq��������/��J�$I�$I�gp�)��b'�Q�����	s����V�$I�$I5��L�cT�Z���EmtlW�5��V�$I�$I���6S���<u�>|���$I�$I�T��m�n��J�$I�$Ic��6S��n%I�$I���gp�)��b��$I�$I��3����m1�[I�$I�$i��f������$I�$I�4�n3ep[��V�$I�$I{��2�-fp+I�$I�$�=��L�3��$I�$I����m�n��J�$I�$Ic��6S��n%I�$I���gp�)��b��$I�$I��3����m1�[I�$I�$i��f������$I�$I�4�n3ep[��V�$I�$I{��2�-fp+I�$I�$�=��L�3��$I�$I����m�n��J�$I�$Ic��6S��n%I�$I���gp�)��b!���1�{y ��t����p�s���Co��$I�$I��vfp�)��b��>��`8�������a����&'v�-O�
���'\�dX���m�$I�$IR�2����m�vn��C��
�������xc0�� I�$I�$�)��L�k����w�'���]���[I�$I�$�7��L�k������������{C�"�[I�$I�$�7��L�k������&'�o�{�n%I�$I���n3ep[l�����f��'I�$I�$�#��L�������
���?b��w�}O=z�?�>|���L�?/����$I�$I����m�n�M��v�s��������{�����C��=�sw�I��������c��+/���TgK�$I�$I+��m�n�M����k{�����
��j���Na�z_[�m�|5,<��04�z�$I�$I���0����m�U-��������5s�Eun�vxyjC��GH�$I�$Ic��6S��V��v����#�]���/���!I�$I�$�=��L�[���y��9�!�]�z��;���!I�$I�$�=��L�[����;nf��Zn�b�J�$I�$ie3����m�U-�����r��.�[I�$I�$�l��2�-fp+I�$I�$�=��L�3��$I�$I����m�n��J�$I�$Ic��6S��n%I�$I���gp�)��b��$I�$I��3����m1�[I�$I�$i��f������$I�$I�4�n3ep[lUn��z�0{����+���$I�$I�V6��L�[�����:��Fn�b�J�$I�$ie3����m1�[I�$I�$i��f�����m���
O�9}m0<V���
���*I�$I��/��L�3����/�{^�o�
�]�~q������d���?��5Q�$I�$IB��2�-fp[�#��gw��'�����.�����&��$I�$If��2�-fp[��z���x�3��;s��KK�$I�$��hT�������I��a��[o��f^~���o�����p�QG���>:\������CC+?�2���������kN�o������Y��$I�$If�
n/�������_��G>�[w�uW�/��/���c����>|��
�������/~1����a��i+=�5���������m[�^k��t'}54�3-�j'\�7�$I�$IZ�4��C=4|�3�	���K8�����\����KG���3'����������&�l��w���>���7�8|���tP���\a��X2������2�-�X������N>*,:�����cC�uW��7�����!I�$I��	���v����?�i���~f��9b�z�������l�M�2eJ�������>l��������w�����fp[��mue���;o	�v�6t���������k���1=�q�~D�$I�$Ic�����j��?�#5���U�i>�C9$|���L�l8��
����������=���n�mp;����f�0{��������xMK�CI�$I�$�����'�|2�����N
>�`8��3�/���K�)���2:�'?�IXg�ur����w�	k��f����.���:���F��?�D����s�k�Q������GH�$I�$i�k:��������<��?���n��������>���&S(�w�}�H[����I0��V[�������n�����������}�:�an�b��g�0��{�GH�$I�$i�k*�e~��;,�������v�m���������/l����o��o�����KF�N�6-����a��������e�G`���~2���v���>����_�4�3��I�$I�$MtM�7�|s��s�=a���I�JH�4	���o�����0y��$�m&��c�=ns���an;��~��F��$I�$I����*���/��Xc���f����g�W_}uLF�����Y�f��3g����Y���k��e��u��a�w����������o����T��n��?���g�1'�������t����k��)�=O������mJ���R}x��a���mS��u�����=O����������n�K����X����U����s�k��W��3f,�\Uj��F��G�~�t�Y7^fo�An�b��������\�y,��,��,��,������w��iIp�h��$�]o���9k�~�����|'l����_>��?����Fm�{����[��/����T}���!Y�yr�����sz�`�5r��X3��=Ly�����J���w�zG���];#<��������������]�y��&���mS��y�����z�Ya������X3��ex���{�2u��o��S���<wVx��e���=w����v�z��s����\�����'��m[�ny�����z�y�}�nn�b����j������jq�=��I=��������,��,��,��,��FWS�LY�}a��$��A,���2��-A�[o��B0;c����o}+yL^��#n�[��q�����\}��#ng�w�=�����J������m�u�]���������mK�KS�{����I#���w,{��W�����}��a�k��{�2u�csFq��e���o�����Gq;��k��w�Y�����M��}���e����G���w������� ���������]>3r����+f�3o{/<�������>��,��,��,��,�j���g���[��K.�$\}��a���s%%������f�0w�����������|&�u�]+4������m����L���8�mu�q[�X�q;�����Y����:v��;��y��w����
ou����k�$I�$IRIM����j����>��p���.�r2����_����������s�=7	mq��w&?�v�m���S�e��;��c���?������V2������vn���/�	����u&/�?����J�$I�$����[�k��&����k��7���{�p���'�j��b�d�,mzZ������>��O�-��2Y6.Oh����&C���&�n�3������g�?�cq����7�^���[I�$I���������?��d�O~���?���>�������a��wO>��r�g	d�B�����/�>���&����w�=����#~sZ��Vgp[];��2�<��{iOxw��=w%I�$I�>lF��dL��������:+���~a�������
���NnKx;}��d~�C9$z����+�h��X3���������tNw��ap+I�$I�4�F�Nt���V7��[~����$I�$Ic��6S��n������gw��q+I�$I�4�n3ep[������tUO�9/?�^�0��S��0���|)��H�$I�$i4n3ep[����U1�|���s�-a����E����sO�������$I�$I��L�3��nUn�:;��?���k��\��l�i���Z�[I�$I��Q2����m1���V����O��9[~/�]���+/:m�$I�$I�(�f�����mu�Zp����B������X��)���Q���o�'�O�1^|w0����Cf��$I�$iap�)��b���j������{n�1�t�Q�s3�)w���.�	���~y^w����pz��y����7P_P�$I�$i3����m1���V��v�^�\an�l�*���9�<��9��:��#n�
3�/���$I�$I��m�n��V�����<�M�jUp{���a���s��7����I�$I�$MH��2�-fp[�*���mn�������[���G���)���$I�$I��m�n��Vgp[��W��u��oW������4I�$I��qap�)��b�������9)�]�n%I�$I����6S��n�3�-o�{r���F�-���[o��7^��Csk���`���$I�$I���6S��n�3�-�Lp;���8,>����$�|����N=6�>xO^����$I�$IR�0����m1���n�+��=�@�����c������;lz��������$I�$I���6S��n�[������f����v���v��7,8��������qp����H�$I�$�	��L�3��nUnyH���7s�k��������_�,�M����ex��%�$I�$Ij��2�-fp[��my�
n�������6���t�0��K I�$I��&n3ep[���:�����'�sD~�b�6�e��Oyv�$I�$I����m�n��Vgp[�17������X�
n����Z�I�$I��6ap�)��b����gp+I�$I�>,n3ep[���:���n%I�$I����m�n��Vgp[���$I�$I��0����m1���n���m�@3:��s3�����o
�7g-w�J�$I�$���6S��n�3�-��������m���7��_]�v=�;�qaO8����]�R�I�$I��"��2�-fp[��myc�v|�;���KP����������b�~\��;���^�[I�$I�42��L�3�������n���Ga����<�����p�5�a�#��E�wow.�;I�$I��Fn3ep[���:����9��58�!�M��9�;������pooxyj��n
��^���,t�tm�{��0�h���$I�$I����m�n��Vgp[^;����<�x�n||W���`�K�=|_Xp�oB��k��k����c�o����i����04n}����N��en^F-;5$I�$I�83����m1���n����-�(<3}Yp;8��0��_���������(���	��~���p������5�����p�g�k�$I�$I?��2�-fp[��my=���zsYp�{�a�O���X]�����?�:F���@�������o_�v������$I�$���L�3������U-�����������������P��GT����a�3�������6A�$I��qfp�)��b���������>5tn�Vn�b-:��04�u������_��o}n �� I�$I����m�n��Vgp[���.:~����V����;�5��'����e��$I�$IZ�n3ep[���:���V����B�����X�n��w��m�5��-���
�2�yq�vn$_�6�v�:��$I�$����6S��n�3�-o�����KG<[��EOn��5���������^��|��'w������������;�C���$I����L�3��������ntlWxn�����n�{7�>|_�����}�����+C��w�������o��hx~���p���a�b�[I�$I����6S��n�3�-o��?=�+������(����o��g��l�i�X��K����a�����_��R������a���u
�r���������P�$I��U��m�n��Vgp[��mu�n��C��g��M��m���V�N?1uTo�����7���k�����Z�$I�$iUep�)��b����gp[�h���E���vO���Q�v�.��b�|������kS���]{��V�$I���3����m1���n�3��n����{��y��1�m�:��^�{��d�*�	n���8<��@��$I�$��n3ep[���:���n�;��������5����{�
}�?�,_E3�-�����.������g�g�/�;f���$I�$���m�n��Vgp[��mu����wL�>mp���=�@�|!�}�s(\�h8������z�nt��^����/<2m0,�Yv}�$I�$�
��L�3�����<����$��U���'�WQ%���^�{�������{�]�����W_�]���KT��{8�uo_�a�����w'#p�� ���/����^��4����3�C����h�$I�$id��2�-fp[��my������������N�~�M������e������&��ukZ0��d5L���������}�m���p���a��{��N�[��U;���`�������C���$I�4�f�����mu���V���Cs;���&�������9�o�8����+���@m��n������Cs:C�3O���n�7\�T�����W^l��Gt{A;7������[�:����v���{^7>=��?�R;o}0�]<~�����xn�`�����s�@x�]���$I��r�f�����mu���V7��[���k���Pv��[��)V�Eg������(������'��17����.���v_yq�����^O�Z-t�h�0�_����m�kHw�p8�v��S�t�_�����Mj�������s���E��z����[�a�
�a�Z_�5iI������pvw�������e�������h[�����g�Dh{�S�a��k�����Y+�~`.�?M0��$I����f�����mu���V7����k��g�/�o�&�!�M��xd��~���{���#����v�n�yn���^��tu��^Y��[�����-�-\��{�vL^������SB��g��;oI��V�XFg��{�-�
_�����������~r-�����mT����l��G�������1���w�CoI�$Ij5��L�3�����<����"��������G���(�v]z^��t��v�Zt��0����G�w�C��G#\c����?W�:�������/]����������Y�LS
��^S�����wX�\��l������������a:�������[n�-��g-	��ZmY��^=��~��s�5-Q�(>?�;�)$I�$ie0����m1���n�3��n,��9?�8�YU��v��'���'�]�Z���l����}�
nL:(�MKk���/Pk�f���'/wLY>r�,8�7I������J������#�[2OpqN��7��Xv��?|�\^��y�o��}��t5'���L���.��]S;?$I�$ie0����m1���n�3��n�n/8#����Xm��je�j����#����������Mz�4O����n�ur��`��vQ}+��qS}�j����t�J�$IZYn3ep[���:���n�[������	s�a�[��*�v�|m����X�8$��V��]�d2�m^�be��E'���tu�pU}�jn%I�$���L�3�����<���n�[U���+.J���k[�V�w�0�9��<�����������C����^3�z�/���\����$I���dp�)��b����gp[��my�����/	�����*��|/t]yq���]�����v��^rN��s��u����%I�$���L�3�����<���n�[U���;ns��$�m�n�U:���������6�]�d�<^�h�Z`Vm?��`����p���5�������Ca`����pWW��r�����s���9�>���d��$I���ep�)��b����gp[��my�Jp���]�OS
n��6���Zp�~�m����������Q�;s�����%}���K�����a�S��I��-���������=a�A�	���f��z�����G�������+�������$I����m�n��Vgp[��mu���*�-��#������2�
n�_����kn�b��=�x��q]�������s��������O��+�^k�����v��5./{�$I���ap�)��b����gp[��my���r���S���~���Xs~�Y��eU��9��7�M����'�������*��k���?�%�gI�$I�gp�)��b����gp[��my�������6��_Dy\;���x��|Nwx��e����KB���mW�E'��v�!I�$���f�����mu���Vgp[����-5��v�n?o�T	��)��s�K��/^|�Y�c�5r���V�$Ij_��2�-fp[��my����gpkpK�sp�������S��Y�4��6���$I���n3ep[���:���n�3�-�����j���k�o,����<)�M������E��K[|e �'�o�
}�reI�$I#0����m1���n�3�����<�[�[���Xw�pr|qco��������F�X��Q7���^L��$I�42��L�3�����<���n�3�5��n����`����������8>_y���$I����m�n��Vgp[��mu����R���{�?����x�����x�u���u����;��$I����m�n��Vgp[��mu����R)�������A�k\������k������.~8�G�J�_�������)�����9����7=��\����>I�$��f�����mu���Vgp[����-5����k/������X�n	B�������v���p�-�����6�]���'<��`Xv�I�$I���6S��n�3�-���:���n
n)��b����h?�6:6�<^{��pt�ufV�<�$I����m�n��Vgp[��mu����R��������y������I��=��7VW}����
�_ym����=���5F�$IO��2�-fp[��my����gpkpK�+���z��+9W���k��������v�zn��e�@�I8������gv������$I��n3ep[���:���n�3�-�����2�-6��vp0��{g������������������=7~��P����`8<7c0<\;Ozu <��`x��wA�.K�$����6S��n�3�-���:���n
n)��b�
n���	�����Xj�qoL�?��f���j��S�'�%�%�=�������a�S���k���k���W��;��R�J�$i�gp�)��b����gp[��my����m����~��������6������(���v�s��Q�i�~
��Z�����vc�����s�m���SI��*��=������������^�%I���ap�)��b����gp[��my����m�Q�����~���Xs��4�N��2�-�����7tn�A����I����@���K�P�����0%�/�m|~�w��������CCa��+-���O���
����� ig����A�$IR��L�3�����<���n�3�5��n��j����7�����Z-�m����^v��u��a����1G��:S�������.� ,>�����3C�uW��g���}5����^�0���l�����}�����B��nO^g$I����6S��n�3�-���:���n
n)��bc����OB���Q^�����{~qZRk��v|K^���?lxL~�bM��7�^����C�%��9[m�\�:��z��~zn�./^T_z|ww'K����c������t����
o%I�0����m1���n�3�����<�[�[������v�|m���mW��G����x�?�=9�]��n��B����9[5�����S�_��8x������r�G�v_yQ�g��+I��%n3ep[���:���n�3�-�����2�-���]W]2�k\����j���)]����?����6����B���'��R_��f��7��?^xg�v|��CK_;��y ��n�����o������$IRdp�)��b����gp[��my����m�U.����0{�%_H���+��;'y��kS����.� Y�Uv��k���n��^�~uQw����0���p�3I���5n�Q�����g�!I����6S��n�3�-���:���n
n)��b�\p{�9�mJW[��}=,>��d�V�����6~qn�y���]��G������kW��6[��$I�n3ep[���:���n�3�-�����2�-fp[�X����OH�o�N>���}�q�
Q�uW��+]��$I�n3ep[���:���n�3�-�����2�-fp[��O���7`�������c��ym��}����_^����$I��f�����mu���Vgp[����-ep[����;���T|������C��k��p�?v�[�����v*,�������e��q7T����K�F����$IJ3����m1���n�3�����<�[�[������v_uq��`��v�2�]���]�o��G+;�]T{�z�v������c����i(�yq�v}��v��%_�v�cK�Fm�t����I�$��f�����mu���Vgp[����-ep[lUn{n�!tn�An�b�._??�;	I���������e~]{-Y?���&'v����=~�-�,��?9m����G,;�����z���H�$�f�����mu���Vgp[����-ep[�����n�g�y�'��B������F�;�U���Z��p]���2�v<�M`z��_\!�M���w/�'I�dp�)��b����gp[��my����m1����"���d��}�����P&����������*�}����]�������5��oW6�������6�����p���?��A_m��_�;���������k�}����S��JZj/e�j�,=k?��9��V��+I���6S��n�3�-���:���n
n)��b���Vn�T{������W��Y�]�W���������[^���w�R�(����q����/�I����G����c�@�L�
-��Y��9������K���j�\�n|z |0��$�'��L�3�����<���n�3�5��n���gp[=��������V^p;��gL��<Q;�}�=���
�|��B�������v�#�n������2�p�2��?��]��@w�pr��z��k�����Q��{���4!�k����c������L�m�=�i��[������1s��}�r��_���C�����i;|9�p����c�R������G������1�;�������9^5>n3ep[���:���n�3�-�����2�-fp[��m�������Q*�/^��?,���0w�-��-7���� ���������|K��f�[���Z�7�h����p[������0��������v.�W���������\�Pxw�3���j�A��o�z�V���h������k�x9_�7������4�yhE���W��tCo��v���e?�|nw8���d���Bh��q�S���3?���������^�,9?�c�|s�qD���/��}�S��;���0�����h�f�����mu���Vgp[����-ep[���<�����
%�����~�sn�:6X#	t�}��ty��2��H�����/�=C�����Z�{�m���[���=�p�wN�����_HB������]�5��������00������I��������<����B�~���a�I+�m�Z������k����@�}������N�NF	��dDk�����s�@R�:��j��D��7>JB��~[����w���6*���q�<�k����
=�
9��2�juQ~�{����e=�����~��9��ww���fT�;m0"�Q�o����^M������������~&bDu�C�Q8����n3ep[���:���n�3�-�����2�-fp[����n�����m^�(��\'���$����O�jmo��k7��>��kL�5x��Z_����`I������!������/�K�e
�z?t]pf����a��_]�ok�������o�������G��������2E����[r�Yk��}~3��u��}�E-o_�������h^��
k�p{��oh(����]X���v����������u��L��2�2��/9��v�&��M���&x�`��8�^{��W�h��/�O8O�p��k�����5(��j����-�_��2��Z���/���u%��.��Cf�m��v��K�D�my����C�������kz�&'.���W;?~Q{��������+`���X_cxvF��}o_�����N�yCk��������nn3ep[���:���n�3�-�����2�-fp[����n�j7���;=�M�:7^+t]tv�|e�����0��������O���v��j��F%����ym���/Z��
�s��K�V���.N����~}��"�e^L�^��v=!,����dZ64#lL���~�����NXt�1�����#��f�/s���X�<�-���?0�m����0�����'=yEp�����dp0u|��/t_y��}|�9��n��O'�P+M�]cvo����/_���.�k8/���(����p��2�mG�����-��5���'C�uW,��t]yQ��@��L+����-��Gw%��x`T���$Am^�H���w��7k��V�&&�m�F�.��5v��Y�5������\E����%o��2�#���k��7�_6bp�)��b����gp[��my����m1���n���-:�����������1�M��������h&��c�|��R�������?�B�H�����'�o�>�����1��`F���sG�������W_���Vs��^���oN��L�
�%|�����'#p�$�����.[�v�.	��b��_�W���;������`�����5��c~__��'��mS�~[{�I���/<+��j���:��zm�ozn�.��*|�{��c���u��M�������-�=��'7�N�r���	����_c�8�v/�FT/\���?�N��j�Z0����`��p�{u����QB����������?�7��,>��04on}����4���k[,���[r��������e}X{�i%��H��FYne#�$t/zs��8���j���E����=qm3�|��n�/���_S�ws�L��f�����mu���Vgp[����-ep[���<����-��r����X�
n�y�:TU3�-�*<�, ��:��0{����3�}���lI8U&�M���w�m��=�^__�:�G`N������O���I�ak�N[����?��$�a�r6��{����#4����Q_��Q����k���s��s�E���^�[4�������|&�^x���s������k�C���&���j����e�^3�-�a�\�['-�Z�;���s�����I�����jFU��&�f�P�`�kW����Z'r�Bh�*^�x��U�n3����+���u�y�����C��g��g�l�}0���6���1�6��+#Y�>��)���.L���`�{������r�o���UK����8��;�}���^O�1���6S��n�3�-���:���n
n)��b����ip[�������N�+�M��b��i��Q^����p?X3�]T��[zG|�����!�*^�p�:=��0w��s��`�����m3S%��9mJ�x�C��&Y�kS,F���~S���	n�(5��9�n�B���g�z+����ymJ�.��dL9Q�f3��Q��/OM����<[����k��-��$���g��=�_��f���$��K�Z����vymJ�r���@�����*�A?y��-�LpK�}v�o���d�+/�y{��b�����a���p5L3R�Ep�F6�e4p�<�M���������iPZ�����X~v�����v�'��o��n�1����d�����"�K�1ob����>��
;�A��]�ap�)��b����gp[��my����m1���n
n��m��g��$�M��������U�
n��#�M�b:�Va���-�������$�����n;f��<>�M�x������#�+��������>�iF�{Z}�j���G�����&i�����7t_~A�B��6y9���~��c���j���h������[��k��Z�k-;?P&�ez�E����>j����{���>�����U0�Bp;4�L�}�e��89�j5�_%��O}n�r5�R?:!�vw%yLn�������[����}<R��2�C�o�����p��>�w����������/8vn3ep[���:���n�3�-�����2�-fp[����m6��{��0�����)�����G�9O���^	�
�s�n��h�[F\3?e��	ny-����r���:_�������up���k?����c�o���On���2�-��2Wq^�b���&-U8&�m}�V)����v�.�}���|��|���ymJW6�%�������j@2'tU��������u�}�X�y�J�
���@����>��u����o��6S��n�3�-���:���n
n)��b������>�X�����m�ep�b��3���2c��yR���
n�<���t��}�����6�M�\���`c��m�G�K�3��9#\���t��r�G�Ip[+��m�R�m�>m����-�D��z���:�M�	~7tn��~�����Z�|���=�� o�����
��Y��a�������2�-fp[��my����gpkpK�3�-���=�������sU��Jx���ySep�b��#��e�d�����������nUn��|��*�M�:�N�����#�+�&v|w��v�jUp�v���� 1���������2�n�-�MK��j�UU*����88�]���vx(�[5�mKk������b��c��6S��n�3�-���:���n
n)��b����gp�����oW����:��jn�up;onX|���m������EgT�n�Tp����6��U�-�H��?!������+]�
n�r���-~�[.�H���k����������+h���8�q	n����G�������������Vk�q���6S��n�3�-���:���n
n)��b�����3������1nO?����n�k��v����}�56�]�F�:n��%�W�Lp����a���L4�-9��g�����Zul�������m�n��Vgp[��mu����R��n�3�5�5�-����Q;O"��en���6��\rn��}(�[F���M�|+|(��Zun����+�����d�1bp�)��b����gp[��my����m1���n
n
n�5��1���NS�K�Vgp[�X��=,8x�d�V0�-�����en�3�����<���n�3�5��n���gpkpkp[������V��v���c�o��+�������������s���vI��gp�)��b����gp[��my����m1���n
n
n��Vcp[���r�4g��r���v�������n����j�9n��t��|���Zvn�������m�n��Vgp[��mu����R��n�3�5�5�-fp[��mu����ip��W���w]�|��v��k����,?Fn3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn�3�-�������<��L�3�����<���n�3�5��n���gpkpkp[������n�3�5�5�-��6S��n�3�-���:���n
n)��b�����3�����:���n
n
n�3����m1���n�3�����<�[�[�����my����n�1�����<�[�[���n3ep[���:���n�3�-�����2�-fp[������m1��jn����;0I���l�L|&���m��l���9���* �P(��r�P�9��VqW��D��Oik��������3�8���o����n��nW+n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:����Zx������_.���p����{��'��1#���7�%��M�\rI���c��������|��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n���[�"g�9����j���|�3��o}kx���~���8 L�8��;-�h����|gx�[��W_}u����Fq���6�m:��|��(n���6��6���VqGq���6�m:�[���6�~�[��/~�����~6|��_K/�t3fL5jT��W�>����w�9L�>��-����},,��������<��"���(n�Q����MGq���6����P��Q����U�*n�(n�P����MGq��U���/q�#�������K/�4��;���ku��o�9�1"|�S�j;A;������#G�_|qP����|��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n���K����a�-���vZ!k� d�?���w�w�g?�Y����X�O�<9���?[o�u�7o^�wC��6�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:�r���������g�}z���>����-r�!��������/3���[�+��2��H(Q�����Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��M'[����N<����~0�{����C��do�qXc�5�G)��]�*����n��G}tP����(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n���<&���K,�D�dO=�T�w�����Q��������G_f��o;�������zx��g����6�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:������p�
�����rJ��o��[<.���N
���Zq
w��������C=�Yg���8q����V\_p��/=���)1�������i_?����q!5���7uJ�ur������h����n���\���}l(�����z��X��������������L���������a�K/�]'%��o~whsNe�?o~xa�����m�����*c��.�f�h�VN�s\sn�xp��v>�+������w�������>8���i�������V�3�[���w�*c�%��y���]+%��x~�76.�c~����}��0c�Us*c��c���]�Z�'_�6<�9�2V���������_��g��u��a�s����\1?��C~�u��0e���;��0c�us+c�����;nY�Z�	���-Ok���U�z5����2�}�Ya�*��*c�{��O?�v�������~S^e�F'��0��{���S5f_~Q�ur�������h�����x5\�P�/� L_c�������]��'k�VJ\v����1�y�����������{7�T�����v��8����9U���Q�~Nk�?c��T����a��7�]'%��0?lsFsNelt��p�������a�����Y�����B��r����.��[�#���7o�����\M�uR��u�>��z��Z���{f_�Z�.��3��>�\��R������o����\8?<�����f�_cNeL_v�0��S�Vj<�����y��������+[k��=�����u���[k�g���_�??�����*c�s������x�����ck����c�N:z�k
4&���]��U�o��|����{���5�UF1���?�������u�m�9���4�T
������+����n��8��W���T����fl�Qcne�Xo�0�����?;/l{f<�uZ���G*u|���9Uc����]'5nn�M9Uc��_�y����
�;�1�2g�yR�ur��Y���\�����c��y[cn�����m�I
������Q�����������.����i�NJ0�{M<?���9��W��f���������?�v��`��fk@\�c�p���>���9����3w�f�k���������e�!��[k��=��������["�}���k��KS���[cHS^e�=���Hk�.�3{V�s�u�9����l��/r����9��-���q�Uk��y��i�=�.�y���w��J�Z9�'X���{��y����u{sne,�����"��o�8�:��$n���]w�u������aZ��������~�+_	���J���s��
�=�Xx��G�b���+�w����?}�qaj��4V��xq�-�����v������a���
���_�=�h�{^�cSF<~��m�I�����S5n�����?}�Ia��6�T���m��������W?�4�1�2�=ej����{���6��K~�1�2�>�������]+'V?rVcn�����z^?��S[u�Dcne��������������<iZ[���Vaj���9�������]+%v9���@���_�|���7����]&��ye����+/_�Z���|2�}�����X������'��g�Q�����k���-7�]+'�:���tex��/���c,|�����
Vm���WZ��.�`�k
4n�����q3s*�1����y�3�^�C~�0~������]+%h[+���)�2v9��pC�-��yq���"�>������M������s+�>~v����y��c��+�l���v�2<��k���'_�\X��x�p��p������wh���sx�uRc�_���S5�������0i�5s*c��+��.<��:)������s*�1�����y�����Y�1�2��s��|k��rb��&5�V��.|���O����6����k-&�sf�uR�����Ekk���5��~Q���pt��l���l����k��IW>���w<}J�e�:����?�ox���Q�x���\+5�������Ss+c�#f��~�l�{�>��>�1/n�Ik�?���Z�;$^�[�<5�|������=<��^�9�1e���g�w�k
4�c���x�y���k*������j�y�Q�1��v����5�lx\�c��7,c�>������:�z��`m�>�)�2������s&�������6Y�1�2^^c\x��s���W���&}������U��	����S5^�l�������?��S5�g��3�=��]s*��q���]''����>�1�����'/��1�jL^o����sqSN�����/����l������_�uR�1f���c�����_����*�O����������Wi�My��:�\>z���>�)�2�.���>x�E���<�X8���s+�}�~��N���n�%��������2v���5W�]+%n����j.a�As���x������s����Q���k
4|��pac�b��/���=���y-<��'�v�����G����^S~e��~U���j�15���}-k��1��w������k��n�����J+��|�3a�}�
3f���|�2�n�\r���K/������o����G,�D����=����<%L��$��]��<�Z�W��\8�Oq{�����\XS��/���w��v��X���%�x�����p�ajk���S�w�"L|������97L
c�������=���'o�Y����}��3�3O<�v��X��}����y�������0���>�[��w����7��gos��p�C�x�n���K������y���k���gOK��\39<��<{�-��>��NYeTx��k��@����R+>'\s�=�y��#������=L����k��>�Mmmj�ex��/�G�XP�w�^��qSV����E�5�`�����D���s������N>6L��$��=wj���]+%N�zrq�����������8y��s��g��v�����7�:%~a�V�������p��E?h�����n�mm���J�3=������;�9=�r��1p�Ovn��/�xL�uRc����E��Q�����/o�vcNe���*���/n�NJ0vlvR�n�=vv���������
S[�������������m�VNt�����q��Sz^���r�cye�����v����������p��g�������>n�M�}�x��m�J�����=$>��r��p��o�c&�_�����9�A��x��\+5n����Ck-��[�5'�}�����p�����u�������s�����r���p��f��~c���������i�����^:��E�5�`�q�%��1��W9����=����y�Q�1�����m�1�1��i���>�1�j���^''~|b�yk��[#~6/�����<���|����xe�����]�v��������}��������p�y���s���[��v����5?4�T�MO��������c�cf||���������Z���Z�U�1�]uEcn�xe�U�����M9U���|��Zc��?m�����<��:)�sps0>��K_�y{�)}I��G�go���Z)�:��5 ���[�L��'�(��M9�Dk�>�~��`�s�e�2\���:������{�	������e�����k����>Vo��My�1��y���XT���'��}��X��1r�E�5�xj�3������S���j���Y����a�n�4�� ��U���	<��?����<`~��,�	�s��c�Y�kYc�������E���c��������+y���������`�
�RK-&M�4 �������g���3n�������t|����%|�m�q������>�6�����g���3n���>��g���oq��k/�����o|#|�{�]tQ����T�m��������<�������~qjw �X�Eq���6�m:��|��(n���6��6���VqGq���6�m:�[���6�~�[�{�w��_<�=:�t�M���S�L	������7���������=��=���'>��p�a�
���rQ�����Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��M�_��/[}���G>�����.�����m=x������	'�>��O�Q�F��#�?����v��O��a�����'�����:��6�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��7�|s!m��������-�_86{���=s��	���_����>���}�;�>��O�����k[�h��n0P�����Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��M���v�e�-N����#�(�P�sq����0~��0f��B��x�	&�I��m>��|��(n�Q����U���8��t��[�m�m��|��(n���t���do��(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q��(n�Q����MGq��%�q��(n���8��<��(n�Q�*n��(nk������Gq���6�m:�[�-�����MGq��U��Q�����Gq���Vq��MGq[�m�m>��t��(n�Q�*n	�m�m:�[���6��6�m>��t��[�m:��Z(n�(n�Q�����Gq���VqK(n�(n�Q�*n�q�y(n�Q����U�*n�Q��BqGq���6�m>��t��[BqGq���Vq������Cq���6���Vq������8��|��(n�Q����U���8��t��[�m�m��|��(n���t��P��Q����MGq���6����P��Q����U�*n�(n�P����MGq��U�������6��6�m:��|��(n���6��6���VqGq���6�m:�[���6�m-�q�l�v�n���K~�1�2����mFq��%�q��(n���6��6����P��Q����U�*n����}���������	�x�������������Bq���M��\'>Q����������/�����P����8��|�y(n�Q����U�*n�(n�P����MGq��U���Uq;w��p������Z*����
��F�.�����[�*n�Q���f��7[�1�jtJ�������?,nW���co�!���[���I�2���������f��[BqGq���Vq������Cq���6���Vq�N����Z��c�
��G��?�����}���~������Yg�U��L��(n�Q�������1PqKtb��qK��Z4��������p��v��#����x}��l���Pq�F�-b��'+bJq���N��6�l��*Cq���8��t��(n�P����MGq��U���5q���/}�K����f���������6\q���}��_=�P�n����6�m>��t��tC�������9�G�7�6�%��v�#n��R�6�f��DcN�P��G]��v�Ea��%�*�S�����������X������)���__����O~wJ���������p��v���WO=�x}��H��nP��F�-R��B�(n���Gq���Yj�]||��]�[a�.[��	�v�c�����-�C!n_����Z�*nx��\<��3�l����7���s�)�����*��`���Gq���6�m>��t��[Bq��&n9i��S5:%n�n���r��@�-1�����w�q����6�U�N��K���*n�y�S�>���[����9���G��q��v!��|�t������gMy��)q�|km��S5*n	���"I�N��*�q����)q����S5,n�F����o�>���[bl+�����qS^���]�k�s�&]����j�p�
�w������O.r���g�	�����Fm�����o�O7������?�:�;�9����%h���m3�[�-�����MGq��%�q��(n����w�y(n�y���?<3�1�j(n��.n�������1��m+�TL.���������]���M�,�LXa����S��Y�f���[.,���a�����%e���N�����7�������O3�7���;��z��`���v��(n���6��6����P��Q����U���8��t��[Bq�FW���	�g����za����v!���Z�l���RK-^z�%�m��FqK�q����N�-Qoq;{��:"��#n�k-�&�Z����
R�-��}}���v�����\pV���C�a�����%���.� �\5.�;%n�#��t�v�U��y.����&,�[�m;��|��(n�Q�����Gq���VqK(n�2q���[X������i��3g&����7VL5���������0��P�*�3���v��wX�9�����������R�yUc�SO�]'5V:����R��_��]�1�j�|������w�i
T}������M_3�<b�//	3_y��Z9���}�x�S�{^?�������hM�������������:�����M���q��a��������<�1�j�w��0y��:~��0}��s���[nX�Z�G��68������J���#f�6�3'<�v������������^YP��?��C����f�Z
��-N�;�+���a�����a���]+%���wn�\8/<�j�{���CcN��q��m���'����G_p����L��n�yUc�Ov3y��Z)���s�����?S)��j��3�>��:�q��}�wF�����[��~���q��m�I�;��>���=��J����|�1��������]+'����2<����s��a���5�V��uW�;0�0��pV��>��p�}�z�3���s�����f�6��k�u��S5�:^x���������#�r���C�_�Z������n���p�c~.�{~�{f�uJc^��>~��\��V=����p�����^XP��?f�C~O�w�E�5�`�q��}���\������0k��s*c��k��7��c�xbn����
h�97=\Y�^vacN��>~������/��W?������3{��s+c��+��7\�v���o������2\�����+ex�U�9Uc�v��]'5�o�A�r��V�y��=OO3��1�2f,�D�s�1m���G����
�U����o�\7���s���M�l�Nj07�T�
[���=�=fc���Q�s��m�I�b��c�������������b��a���]+%j���r����5��)o���r���c�VjLj�N�6^���j8��J���yU��Of>x_��RbBk�o��c��o���{�M3���9�j�[|�k
4�M�nl�M9U'���������k�����f\tn��rb����p�^m���p��0�57�V�������8�?�q���&�L�n�����~{?~|�i�����{<�w�)��n��z^�zk�	?�Fx��_��^�n�v��Xb���yUc��.;���Y�;�yU���l�v��Xr�	�9Uc����y���_�[�9Uc���l�NJl���a�=�m��[�������������v�a��k��2{<��W5����������:�ncn�8x�M����rb��x�]�y���k�����F���m�J�Q����O5����V���x�~[m������q��.r���V;F��`cN��x��{�s��%���e�,���[�]+'��~Gc^�Xk�s��;�Q�~������qcn�8v�u��@��c���4�T�
v=��=�-�Lc>��r�1��Q�VJ,7���|�����Z���=��f���9U����j�NNl���a��oo����zF�{�Zqtc^��z�Qa�V�^+%Vmc>�X~��a���y�/W��S5�Xg���������S5�����������1}����Z��:)��.��1����S5X#���x������+�
?��:f��.k����vq����n\v����q��+�]'%�[��w��w(�s�+5�S��V��6���������o�������?�#�r�����[�Z�����k,�/��9s�����������:���1�j�k��)^��v��W[�1�j\�'��h��Xm�Ks��
���y�)����O5X���Fm�J��w=�1�j������9q��s�u[�NNl�����'�q���Z�����q����o�A��Rb�]�o�����hk-xl�{��h����q��%����rLcN�`�)_��vYk�h����Y��:9��.G5�U���x2l���=�9��������k�Nj07�T
�I���Zc�E�c�������cL�s0{��=n�Yc>�xp�������Z)��.6�S
���p�wh��us��K�k����=��]��[5���������V�yU��%�~��fm�J	���|����s5��e�[c[�c���5��q�]���)�j���_����|�1a�o�������������=_j�.^�s+����b__�Z���v�-L�>}��l�+�v���������:�=��Y���/&���&M����������.[<?7%��������Fc�Q�f��	�,�L8��W�Fn�������1j��2#F������yUc��5rb�'5�T�cV�y�&�2<�!�z�8b�k
4F��I��Nm��#���������6�LU�Nn�������1b��{^����G��u�W��u<n������6o����������h���V�����*�#����(�cV
c7�ycN���z=�9pLs>�?��;�_c6<�1�j�Zm����1������#�
Z��~��c���o��#W���=��#�=[e�B�p���7�S����4,�j�{~���6�@��1b�
�:>�1�j�\e�����*�����w��X�e8z��������k���G~[����uRc�:{5�T�Q�m���5[erP?�x����;f�Cs�F�FX��]�Qv��^��u��5wm�������������~���)����?������nS>��I���\'5���|�1f�}�2��/^O�1G4�T��Z��_+5F,�j����[5F��g�{��G2�wb������Tc�?+�J^�l+v�G2���5�h�1F��KcN���>=���5?4�S
�akw`��f��TcLk�3b�u{��q?���U���d�����'���
�����2\�e�����Tc�f��+���������:T�#WX�1�j0���g\��sp�x�r�4�U����P�u���ZcGS^�8�C927�T�����z��]�Q����`�:I�cF�cf/Z�g�~��1��:�dm��O5���k���`��S5��D������Zc����1v�{���)�j���U:P���M�������p���#Z�^?������cD��m��[������h����/�~��h�qc^�����zg������2$��� ��34�Y;n��"��_~y1�����+����e������g�y�0�0�0�0�0�/:p�1�"ny�6�l�����x ��O�d�������>l���a����VDDDDDDDDDD�+��:������7p�=�K ���9������/�y���X���""""""""""�Eq��s��%�\2|�S�
Gydx������>;�����~�x����?���$�������������5q����/���/�w����mo{[�y�{�G(�t�M�����W����������HI��- o�������������_������>��CJ[�^�������f(nEDDDDDDDDD��[�a��VDDDDDDDDDd������?�9��7/L�<9<�����_�f�
���bx�����)S�������fh�������S~�=�\�:ujx���������EN�?�|������f��W����/��OZ��CeD��&N��H��H�e��~�����������_�'M�V�i��
i������_.���G��+��G���93��w�[������>}zt,�^��������e0�591�������e0��9c��0w���k�?eK��M2�L�4��oc~�+?��/� e���m����(7~�r|�&}�G��^z���q��f\������S�Wz�����:�6X������1����A��q���l��Go��5�}�>LN�?�m�k��=;�����1�[}�����Fy�_o��{k�����?���=Q�W�h��(?�#�z~\�������q��S��x��X���&x
kW����=�2�����:s�������<eA���U�Moc!�u�[�O����\��2�����e��}���1�m��O['?�W��e��5MeW���W:6���U�dY����m��#'^�z��}�1�����}��5�m�r�v�By���U����'������u��:�Q6�c(�rL�\����we���he����Cq�*����������o{�������[������Ad����t�Ia���a��	��`z�A�����{��W���o�&����
�,�L8��3��a�s�c]|��E�}�C
���Zj�p�i��p����Dz��G��|�#���O����X��������`x�[��H�3&<��CV�\�>|�q��J����^z�p���P�v��g���i,�j���Z�D0P6L\GqD�������wm�z��:��(,��(�:�����~7������?����F��n���R"s�/�����k��.��q��x}�-���7��������|'���?/N�-�;�C9$l��6��\���Bw�}wXo�����_l��
����{�l�9��"�*�;�f����_>��?�C������_��_a�]w
��w_W�\�kPw�
�Nr��zk�t�M�?��?����}-�����������6�������w���^_���������e�]���[������ga����<���Y�G����g�������[����u�f�mn����~6������>�����/|�a�=�?�pW����:���}����^��o@}������V�/~����s����z�o����8��Va=s���kj�}����|1&�y��]�x���i��z~�/G~����/�x=k�N�c
�=�c�W����5�����}����ZdL�=������1��O�6�d�bn�����L�����q�3��L�'b�������������?��O�[lQ������8|��W��g?��"�O}�S�����_K��_s�5�8N�-_��:��_��Wm����C=T�����7��D�-�����N(���J�o����>;,���:���7n\8��s��k'�7��X���o}���1m��/�����������\�u��~����7$
�Pf������.|��_
p@x���������6R��o�y��4\��u�~���p1�����OQ�O>��"�s���{�]�i�~���'>�����|���:�S�m���z�1�����>��O}�y��c/}�~�Tve����,�����P_��K�1��)��^��3�<S������o{���G?����J+�+����{d�����w�a�b��z�K�L��w^�Z�~M�����W�/{(��:������{�����X������4��A.���0j�����/���.�(:�������]w]Xn����z�;�����X��;��
���{�-�?��
(�o���[|�c+������b��.��Q��`��3FS~�	�<s{w^�m�`R�p�
�F����I�}�{_��~P��� <T0�2H���G��8����}���������_11���������������e`#7����@��B�U~u��e�2�
q�B�	�2�oP����0�E[���[���:e��~�����?;���
H&�z��'����N;���MN��lZ)+���#������"���P@��fD�������6���~�7_}�B��>��o|����y�E1�e��X�=��n��V,��1��3)��s�����[���a�,��-n�&��������/���n�mQ�e�.�
M6M,��%�� "����C]D�R��o6�,���
��UW]��F�X�Q��C�D�0>�G�2"����?�q��-�Q��dFr�xo�����_�yc�\#�_��N��������_^�b�n�l>���f�5b��i��1r��������+�,6;�������~��c�2#h��o��2�t;�N�	�a�i��M����z�\#�}�������r�an�
6�[��%�\R�a��J����5�\�����_���������_�i������X��a��e�]��Q��rdN�������������r�z�'��9�I�2�������bM��5
��g�5����7:��Sz���'�xb��g�d�����@{G�����S���e�����r�~)3��Vm�7�
1P�S!�;���8�P���������7�qi���N�[�}���@�/���)C��G}�(;��3���=�o5����s��������)?��x`�+�����fb�R�y�����/�Xf��@�w'�j�'g�vy#�u,��q�Zfe�+R���E�\����z�$?n�p����2gd�I.�Q^����x=st��\X�!��#�����r.!?�����6A�1��G:u��3�����Q��N=�����Yr �/����~������J����A��)u�M�&���WXa����!n�n�U�+�;���2�����eyW_�������m�-�p���!��b������ATT(����@N,@hh�ud1�$5����S(����Z�H�q�����J���5PXD}��_#G�,�(
��)��1�����-�����;:�A�r���+����v�`B�.<�(��n���K�������G�d����	�'������,��!x��k2i�����/��)?��"�������r 0���A�� �.u�xB�r��	�����7r�T�Z�M���&'����-��V_}�b,g�����
���
.7�XL6�[���;��se}��\���a#�f��S]��; �9�@Y��x����I��+Nxu�2?n���Y���j�H+�}9��HB�qz�v����c&�kNp
N
�G�2.R��K����%?��A8C~��[��`�0��`@�)6�-�Xq��I���8���AX�F�(�e���o3>u�������s
����mo��)�}�����$wr
Q7�<"|���-��kj���47e��+k��((�>��V[��kuq��8��F9����g���<b���/3v�����g=��A�"O����O�QNl�1�|9��8Nb����kn�����9�P/&���g�/?J�/��e[B9��e�~�iqK\���y�����������b��3�p���3�w�����-^����;�@~����)�7������p#�c�`�cL�0�q���\�z�}��P��0q���{��W�?��h����7��i=��Q�RC�tZ�r���ha}���5s���27��S���Z��&�J�v��?�	�->qQ�G���z�O(�uF��'��}�2���)2��7�/~.y��e�������gmG�2�~��������9�����8$�IO���-�cN�F4�1#��2g-���u*b�:f����?7�`��:�c����<���|�Pa/e~�xc?��e/@?��8��8���N����_�����_P��s2��q�,?��vJ����;��7C�Q����\��q�C-��!��r�}'�ZR�1y�X�vC��{�^�>B~�=}����2����O�2�1����]x=s�
>H�w�m6b[8&x*��� ���`����l���/:��F7���F���������i��o���'���l�|���Y}���G�qy�����I{&�� n�R,p������#�<'�Y@�����Q~&��6���������`3��_�#L�l�<,������4�<60�q�1�B���������z$#���~�����w,�<,�K�7n(�`b�g��b�k2O�#w���-�'���{�Z�y7�-�d����z���eC��Q>l`��X��c��f�S� 9p�6��O~����������Jq��.gi�����_���g�`a�8G� y��|_���
�����(���%?�U6��6���[>bI�Iy��c
���G *��-I$�C���Wa��M7�d�n��:�d�m�~<q�8����e
���$�C��n��6���I�RF)������%���*Mm#�)�=6��6����e�FN�>���r���X!G�}>�T$�j��V���E��id�[J��~���� X[3�������G�pb�:���~C��4Uy=�|��u+}��3;t�71rIDAT-n��!�9����<c07+�k�����e^�Xiz=��\�}���h�!��`<��8��io�;7�71�1W |�m�=	r��E ��A��|�����
����s�0~�_��:�=
���iq�Pg�k��knz��/oV0g~��E_/�M��L8m��__O�cs7��g�>� bOWo�AD?k�N���z�yn���cc7}�5!sDoP��w9u��-�m��!�XX����F(��k�07������z~n��ss�wd�X�����2�V�����>�G_�d-����������Nx$�~g�����������e g���g��Y�1rx�P�s�V��S����i���}����,����zf���p���
qK��G������Y_ss�6G~�)�$�M���{��Yk�^�*n[��c���FS�@����`�����F���.&wN�����Z��8�(w�|��3w�@����RU Ja�ID'E�Z���9l�XX��a�A�`�������2��Y`�����nB�� gbc��i� N�����!�(W����uY�C1r
�19R��%���d����PVl���`����X\��7���Mn����wb,G�ubQ�\6f��b��u�$n�T�
w��l��)n\��,w��i�&�.n����y�<����cAG}��Y�2G��M'n���0g�A����t��H������5&n�	yG.l��<��n�[� R��������-y�>Y<���&�?��3'��N���hG\s��,k��FNc����n�F[#?�.��+n���RGn�;ur�����=��-�H��-e$7X8ISn\��O�.8A��:?�q���&�>�Z���[��r�c���^�5���l��N�8�#����k�>76���q���1<���_���k��9�?�M7����xN��^;-n���l�����z���q������e�bO�iU�D�l���q���}2uz,�C~��eMB{�K��q���wZ����S�(���@�#����\B��Z��E�
�!�^����'��u����7����e{���5-7-��5X�wD)��������D�����������|"����0�p�������X'0���j����`���f9����I��z��<uH����98�Z���Y��>s�~ra�-��6u��j��]�t�Q	M����
i�$����c}���p�P����
���.m����3 t������A�;ctB
:>�	��,n����;a�
'5��;��5��w����fs(��k��a�]��c\�A�Ro|���r�MwC����i�x($l\����l���$Y<�p��y�P���� ��fv� �
nb�?X�0����C����(G�'x���T�&���P7a�E
��`1D�G�3��-m�M�At�7��i���Mz�6��@��a�@�4�[6��3��g����e���,0�&�qK{�������+�����8�L��%n��9�k�d��-O�u�SW�G]�s��/qK]2�0^#�����n�[�.���h�����Ep�I�D&���	s���;���A;������fk?�|��M��g�q2��0�������i)@���1�9�'\����>�z����~������eX��&q���Lcc���ho������9��
.���B�D�m��3���&e�XG?@DV�o���sh���n�a?��!;���)%4�g
��^���rd��#!�}����@n
"�����9�u9���B����f�z�1}�Wx=7qX�0.v{}C{b�f��FsS�g��&�7��q�~2�H~�����_�n	��CN�7gS�����0�u>u�Z�O�p3���?��/F��~�n�>�5(�,�?e�����5,��%��>C��)�k�nR�dD'cx��c�����r�&�_�[�hE��S>��u�[���6H�e_�������#�$��:gL�B��?�s]7����a�c��iu>�B�+������e�7c�w�#��y���+��s���A���U�Z�#kE�j�����-�c��n��5i�����3�����c��T��`�V_��^����gU�R�-�H�<r���`NN�A��N7� ����`������OY��W��<�-=���71�H�E��w|����E�`���;�l
�����Ny��GV�&���Ohk���Xt�d�`�f��	%&���dy;R�R'��@`Q�����&K�	�
�F`!�mq[��|o���vl�Y�T)&L��3��AL�V!���U�R�-���cn�)e�
�������k��-���Bn0F�V�E_��zE��?�1r��[��NL�R�||�9�����M���#�g2?v���M����>� ���Y����b6IH�n�"n�����B��zf]�NL�kAN�r
��M�|��_����da�cc�F����i|�������\F��i��e~�m����/N����n���X�:���l�����B���e�#����T��n����'�>A��hZ�2_���{L�gz�[��_���5�gh�<
���:e��>ikHG��)n����S�HP�2���Mn&�,p�0o�#��������:	��~�$2��a�a��~����q@�u��9�y�2en����6O�����=B�56��9�����5��&<��>\=�A�p�uUu���}�����O`��`�������5s�o�G����%'�b�+c�U�\�gE�c����e��'=�'�81�����w�������*k��7���`�[��i�Gp�����WB�d�c�fL����}�[<YS��&uNB"��}�����.�L�l�T���������b���e;.��I���L,N�c�!9r���d<�e�,��b�;�,4�,���E8�
w=�{�a!GY�0�m)&yN�P~,v)?Q��EYE��?����1c6e�����r�Fc�_�������i��o6qK9q���|6d��C��_q[n*9�Bn��OnuS���-k6�l�'K�2\�-}���6G�����0��I���)�i�n��1qK�$wN4���y�?���_���|�I���[�hn
����Yo�����e\a���4����RJ�q���n��������.}����e���9�D����i�c�5�R�o�]��/q�����MqK�p ��O������%�R,R_M������w��������d���@�����r�u���]n�qc���#X�tk�����'�_<���T�������x�<����S�r=�>3�X3Q�@�f\$7�c
uI;�3���9)�-�G~�+�`��������d��G�)��@nT2� Y�vs�D���6�m
1�4g��PNp�ot{}PB~��	���)e~�#�4�Fe]����rda|�
�6&ur`|�F�1��y���A&�o�A���Ms���[7�-eD[�m1f0>3_!b�������o!.�!niO�C�t!��Y�S�	slocu9X�q����r��}������P�8���n?&�-���N��A����!�%���
:��	��L��8)�G=8�R�h
q�2dA��������R�rZ����
w�io��N|sJ�EU9��U����$W�C
b�:D�#��LY��Pf!�4��vss�q�>�B�o�[��3���Yp��g���]�7��el�M�LRIl��0vs�������/,�){6���{��w���$�.�6eH�`��o�v:(���-��X#�(C�Kr�wA���>�\��N3q��7X�Z������
"X�J����/�1a�9�$`�����;7	�8�������_�s�/�(@�wC�R>�'��<A[cU~��9�?������e^@�s��e�w|��7�����E>
�\��
�������^�.{;n\w�|�|$m����}�5�w�R���Nawc�H~�'7�J���2?�m����u�`�[��Z���E��$��|�{���5kE�y���AX+s��u	'����E�2w�)����O�.�_�������+}��{��������_�������1�	�$R��o@����o>���f.�L)��m�&���h+�m'�.��������M���K�	{������	X^��������`��m|b����m(�m�{%�t�~���i0�m�"��!o{��y�~B�c^���h{u�-8
��S
Mg�`0�(n�0��	b��D�#5��`�
�<��d�:�`���$N\��f�J0Q1���aBgp��a��AdQ�b��yl��W>�����q'�;�l|;�:,�x�rl8�d`�c�����)U�+c�P6D��������G�� 0���e������,��do�����o)�&q�k�w�}���$oq��G>,���q3�#�����"n�����w�Yh����[�O����K4�'����M{�����n��Tq���m�����-�����i}�EN�r��Y?t���[�e�@}#�k�.�}�.n�7�)"�5t]<�#m���?�7:I��5�[��f>F9S�l~�8'm���:��{�rL���s'?���O"��4����?���
W��N
H~6�S�5'�8����K2�
��%?n�!�1��b���T����l������+N}Rn����'m�\�{���A������qO~�Cx�J����|���C8�sc9}�����S��#3�R?����H���)Y�1>!��_����Sp�"Dn��������E��s���;~!�NR�y�&��A�+ck;�8|Z����M����6����duHy16��aA�������=
��:���d���L�A�M�:�.����1@�w�W��������6G1g�������7}������������%�c"7J���*q\�1��A���B=�>yV/r�q	�[���Fq����*��f�R�
���5�m80�-<9�/�DYD2X
��b����rS���ko0h1T���[ UX�7�80i����������Tl�����}��+lb�F�5��@V�������"7
X���Y�7���h��u�>
�1q����d��f���D�����S���[�6o���sj��n��;M���oS�,�y��@�;z��Fn�5�'���	�q�&�2��
#���z���u����f��&�A�-}�6����vz�1qK�''�����8������#�?�q����|�L���1��9|�O\�9��?i���c�����4e�M���qb�S�$c��w�`���|"�?s9w[���10_!a�b7���l�y=�U�����;���e>�\�X���:E�1�ur��-#�X7qj�S�����c�T*�7�����[�����|�P��������L��N�[�c��n��vu��7���#�9d���w�'�%7:�.�<�;"�5V�c0.�/7���y���X#s�aH��O��u�#�=����U�z`]���Z��}����?8�����n\��L�Z|�[��*����������G���Z~y�`<������d|i�z*qK���pb�z����,�����n���
�m�.0h�����
���h�c�,.k!��M�r}>J���	����l��A�Wy�����1��0�u�5�N������#{|��;� �!+�pMs�����3����
�����I'�T�[>b���`��I��;T��(+N�����%,��<�&>�|�F9��$/�
�(����olY��4��`����e,��q�B��S���2E������_����0vs���6��Y�\�7qKn�?c
�����fe�MI���e��7e�s�N�$��n���AL��_(?�v�N)_r���\���H{�@�l��������}�M{7���e<�� 76�1	��7qK��_�oM�em����������-������\SB]#�8��T�QA��O����V����]�9��;6�����S��7�����K�T����%��95V�����-nRl�Y��#�����/���B�����^�u����+5�v���n��tSS~|��q�v�	�&�
A�t�PCS=!��=�9����7��"�Q�v�	�K�i�(cO��������W�o?����h���k2o��������+o��Gj:��xD^<&�Sb�k�m��1}��G_�&�������n�H+�g�{~w�NS~��h��]����m�������u+��P�a��OM�6?���h��>��s�=������q4�3k&�Vu������ wD<m��J_G4V���s�A��p�Sr!���{M7
{�I��qS�	��[���3��M�qmn��e��!�=�9m��3�{0N'�Q��`���y��ye%��Y0S9L��2T'qKcf�e���{�Yguu�(������A���I�ze��N���R�0\�q������}�lo�3�|��P�nn�`req�|`b����B���<Lho, �Q�������9�������#�(?Eo��n���?�b���On,^X,3�p���Q'E���7q,8��p����L��<��M$b��'����-Nra�^~A�7X�_o��:dL�������gN��n����n����m�����[6��E��7��L�@�"���n��)65���O�m��N�f���9���������,O�t���Uh���[��9�������o�6>��|�#e�w��M��u����
�lY����I=n0�v���q�v����6���}��L��T�e��N�������mnH��Z �n�[�c���F�|9L,?�)�����z}.�l��}%�7��2�Xops���k���	��|����x"?�����7S����n<����5c	mi[w2'��������A�����'&�#��O��"pX�s`d�v��q���c@����G������R-6�~o�2�w�W�x��r�#�Hn���=)��y��'c'����x�:���U�	�?���|���O��a���2��=pYgM���A_�#�s2��k<*�O0�B9�_`�Gy��(��c��u���������|������y-�����Z��z�A�Zn���h���%��>�3��M�s��-?���������{b��G��h�\�PN8��>$T��]�	AV.~�4��K�VC)|�'q�"�E%wY���`P�]l��&bl�Y��#u����GlCT��"n�l����(�j���d�F�;t����
p'��B�d2����B��c�e�`��&�rB
���8��nlRS`���R~��"�>���S<���W�#&����8(R�,���r�M��`���e����E99N���X���d�Alt��s���&n�/��)#�	��&�>���+eF�!���-�N`la��30�[6�,���n��,n�R|��(�uL�q���9�J��n�sb�����E���d�uD�Ae^d\����?��<�)gN���,�z��<B���eMM�����|�����_��-�1m�<x�#'g6t�<Cn1FuB0��)+�+�1R�>��csc��ni��>�G�|���C,���NR�}�������\�$��i�e�����z���<9��\Y�����z��N�1�`b��������D���=��=_��,�~�3�-�>f��m��xU��-?��������e.�8��i1�6�G�oS&�)n��N��Rv������������Vc�G~�1����h��G�b��w� }8E�M�r,��J_������}�6O�Mm�C7�>���1��<���u���u�n���?��|�	����c�`�����N<g��1rC�r�dhS~����>�3}���&`�+��|i�G>�����1�A;��1��3�������-#�7�}�6���@�f
}�v���:��I��q����������X�1��z��tS�R�K���C���Y�Wy�.�����m����hw��P��N��1��bx 6��6@>�A��)�L*z�0��-�*>�����2�w���*
6�}'����Oy�p(r�1\�-���61<���xGQ~|K*u`2j)���<f`�^���fhN�����l�Hc
��pSX�s��E8������(?������.�z��?����9iM��C}�[��t��>a^!w�Q���da��K��m��z��R��S"����/qK���`��XC��c#m�y��{7���dq,���
T�_���;�
���
wo��-pZ��f���}��7����?���O;�����Y^u�k�G��-m�
5���r��O���;�S���b��1��c���G~|1	7���p�s8���i,+Q�MS���}l�Y���3��9�������`>c<���My����y��������8���3WK8�������z�N?�����a�cl�u��xR�����
{�;��l���N}�.�!���r��I��������A�pS
�7� >�#��{<��4g��g>���S5hs���#i�Dc��cd}��g��G�w�
My�����5k��6�6�V��}"��7�U������[D.��{�����f�����=k>>���l���&��cM���t�f=B��#�'�'���t��z�-���Q&��������-m���P�5�C��w��N�!%\�>�\R�I��\��b'���[��g����}�O��s����[���`���H�Q�V����cDCC������`&L$/�`e~���n��b�DGYvr`tR6���4�H
���D�]�no\��F[�#�l�Y�p���p�#���<���il.x6�?�0I1�r�<T}�7X��Q��"�x�	%&������mnf������P�?��c1�,7�U�gN� 8=�����[���~K�"�bb�>�XCnl�r7���k���,w���l��97�'���bM���}����E��f���ds��c�A��Vc����/s[OL�� ��[��-��q���/'<�`��"��������T��n��1��_o�nr�t5INu�#mi��H�'yz;Q�����l6�OM�P���U�H�Z�>��7�#����O���s!�q����!��rq�	VN�q���f���C�4��4�U�q��Q��O;c��fss	�����*?�XN�5�T
���{MeC]3�P~���)�$	7;�r�k|NX2�q#��5���H�&=�/N��6n�N589X��o�O1V����9q�����F~�q�,i����|��\���N?��9�SmM9U����u	e�|�	V���G�7�4�uE��Z�?�n�Uo�^�1������I���da��Oa��W�7���1������6�T
�)��/�c���3.2W#k9Q�����N����)�jp���\9���yn�R�x$>U�G�	�T���y��~`���e]���T�s�c�G�/m����>��z�8��(n�Q�}�)Y��&����n�\�
�;c'�Ygq����rf
F�hj���*�o7Q�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�""""""""""�������������0Cq+"""""""""2�P�����������3�"""""-���?�����a��y���������P��i��k��O<1,����c�	���o����������i������VDDDD���VDDDD��[���?�t��������}��g�6�����������_��9��Y�������9s���������yR�w��]����s���go�����O��\�k������u���s�?�|�.�$""""}(nEDDDdHx����v�mF�n���������������������n���{@n^~��a�V�vX!9���M��w^3fL��>���!,�����/3g����3f����O�`�
�g�6�d����|�x�/��p���/"n������?���*����+����5kV���K�J+�>����������s����*�Kp@Xo����n��f�uG�����B�^q�a��W��G�{�����o}+t�Aa������c�sDDDD��������	QD)����N+N��r�)����|�����B�r*8���]q����}��g�;�>����w����}�{_��'?����{���'���,�L!X��_��x��������EN�HX$2R���0u��B�"`��������?��O��w�=L�4��n)n�^z�B����������'���?��'���|�C
m�Qx��g�k�����_�[��67n\�k���S���{��g���>W��<�8�
�?�|!2��<�H�8�c�=6|��_�.�l�����#8����0���G!d�������>V����<��{�����3x�w����i�{.���B�n�����.�2��O�]v�%��G?*�4�-�-r������z����O�5�X�8a��x<'l�z��������#G��S�""""](nEDDDd�@N���	�?�x�N�r2v��7.�-�z����WN�r����:c�����E�^z���;��NX{���S�����7��8��B��T���S�_|q!f�Ui���~��������B,W��{�)��:���{��q�u=����>��c��4b��p�]w��[>fADDDD�:Q�������Q�TN�^s�5������>l�����]w�m����<��z������s�-N��l�%�\���/���������Zk2�g���[j���G ��`�R���?(g���}-|��_^�u��CB�-oyK4x�<�#n���s�i�y���V[�~����v�q���_��x��u=i+"""����VDDDD�&b�/C�"8y�-������5�\�8����y���S�����<��S�{��w�>}�����)S����cJq�I���s�����g������q
<��G!�'~Kn�����b������)�E[>W�Hf�P�[�1_tV�.'y��^<���xGx�[�Z\�/QCN�O������u���!��{�-�����ZHN�w�����@�rb���7�|s!B7�t���K/����K
q�{z��������_�����g�}v�f�m�g�r����%<���?�qXm���G!�EL����@Y��?�s�Ee����_�5}��m�W�7?�[R^~���K���R�o;~����<�S��z���'�pB�DE�"C�_�F�:a���=<��g��G��_N�)Wd/'k��0N������c��-�����iXo@��L��q[����<�v�v(N�r�G}t�+DDDD��������)���?��2�����8a�@Ez"o���S��l��W/�����Y��/ ���+����o?��o~�x�������s��	GuT����]���/��Y�K��\N��5�''Ns"�������a���Qq[J^�����x�.����G�����_�[R��^{m!5?��O�������o�g������|�a�u�)N�� ;y�_�����.�����'Og�yf!m���/�����X�']yD���������A��f����;���9��|N�����E�<������w1bD�������� >��C���$�w���""""2�<����}����_~���#�_J��~����Ed"5���e<����Dx���^|���|}�3�	x`��oS�-���s�)$-�{�x��"/d,��/3+�P� �Xl�w��R����={vq��s��\��y�[�R���%dp����@q+""""CB���{���S�%�?�x!L������/���q%�\N�r������
���z�'wK��:(,��r��U���<O���N*���/C�i���G2��]�A���n(��xEsz9��-�Q
H�q����/��M�����Zj�����}�C*N����~�	c������_�[�a��VDDDDDDDDDd���f(nEDDDDDDDDD��[�a��VDDDDDDDDDdX���.�s�W�CIEND�B`�
v1-0001-Optimize-various-aggregate-deserialization-functi.patchtext/plain; charset=US-ASCII; name=v1-0001-Optimize-various-aggregate-deserialization-functi.patchDownload
From 75d97a066ac81f5a50b1b7618ad9e240f5497860 Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sat, 11 Feb 2023 10:05:32 +1300
Subject: [PATCH v1 1/2] Optimize various aggregate deserialization functions

The serialized representation of an internal aggregate state is a bytea
value.  In each deserial function, in order to "receive" the bytea value
we appended it onto a short-lived StringInfoData using
appendBinaryStringInfo.  This was a little wasteful as it meant having to
palloc memory, copy a (possibly long) series of bytes then later pfree
that memory.  Instead of doing to this extra trouble, we can just fake up
a StringInfoData and point the data directly at the bytea's payload.  This
should help increase the performance of internal aggregate
deserialization.

To make this work, we introduce a function named initStringInfoFromString.
This just makes the given StringInfoData point directly to the input
buffer and sets the length to the given length.
---
 src/backend/utils/adt/array_userfuncs.c | 20 +++++--------
 src/backend/utils/adt/numeric.c         | 40 ++++++++++---------------
 src/backend/utils/adt/varlena.c         | 10 +++----
 src/common/stringinfo.c                 | 20 +++++++++++++
 src/include/lib/stringinfo.h            | 13 ++++++++
 5 files changed, 61 insertions(+), 42 deletions(-)

diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index c8a8d33ca3..78fd0d2340 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -723,12 +723,11 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -825,7 +824,6 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	}
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
@@ -1134,12 +1132,11 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -1197,7 +1194,6 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	memcpy(result->lbs, temp, sizeof(result->lbs));
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index a83feea396..dec29d2b9b 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5179,12 +5179,11 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5211,7 +5210,6 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5295,12 +5293,11 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5331,7 +5328,6 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5666,12 +5662,11 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5695,7 +5690,6 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5857,12 +5851,11 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5878,7 +5871,6 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 170b3a3820..be43bf314b 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -5532,12 +5532,11 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initStringInfoFromString(&buf, VARDATA_ANY(sstate),
+							 VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeStringAggState(fcinfo);
 
@@ -5550,7 +5549,6 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	appendBinaryStringInfo(result, data, datalen);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..2e0bc28527 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -65,6 +65,26 @@ initStringInfo(StringInfo str)
 	resetStringInfo(str);
 }
 
+/*
+ * initStringInfoFromString
+ *
+ * Initialize a StringInfoData struct (with previously undefined contents)
+ * and sets the string to directly point to the contents of 'str' with the
+ * given 'len'.
+ *
+ * Caution: this is primarily used for very short-lived StringInfos.  The
+ * resulting StringInfo cannot be appended to unless 'buf' points directly to
+ * a memory address as returned by palloc.  Generally, you should be using
+ * appendBinaryStringInfo() instead of this function.
+ */
+void
+initStringInfoFromString(StringInfo str, char *buf, int len)
+{
+	str->data = buf;
+	str->len = str->maxlen = len;
+	str->cursor = 0;
+}
+
 /*
  * resetStringInfo
  *
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..4e4d73658d 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -79,6 +79,19 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initStringInfoFromString
+ * Initialize a StringInfoData struct (with previously undefined contents)
+ * and sets the string to directly point to the contents of 'str' with the
+ * given 'len'.
+ *
+ * Caution: this is primarily used for very short-lived StringInfos.  The
+ * resulting StringInfo cannot be appended to unless 'buf' points directly to
+ * a memory address as returned by palloc.  Generally, you should be using
+ * appendBinaryStringInfo() instead of this function.
+ */
+extern void initStringInfoFromString(StringInfo str, char *buf, int len);
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
-- 
2.37.2

v1-0002-Add-more-usages-of-initStringInfoFromString.patchtext/plain; charset=US-ASCII; name=v1-0002-Add-more-usages-of-initStringInfoFromString.patchDownload
From 0b31533674adb90644298c638cc7dfe066ab5bd6 Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sun, 12 Feb 2023 16:45:15 +1300
Subject: [PATCH v1 2/2] Add more usages of initStringInfoFromString

This slightly reduces some memcpy work in walreceiver.c
---
 src/backend/replication/walreceiver.c | 21 ++++++++++++---------
 1 file changed, 12 insertions(+), 9 deletions(-)

diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index f6446da2d6..366b91f923 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -132,7 +132,6 @@ typedef enum WalRcvWakeupReason
 static TimestampTz wakeup[NUM_WALRCV_WAKEUPS];
 
 static StringInfoData reply_message;
-static StringInfoData incoming_message;
 
 /* Prototypes for private functions */
 static void WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last);
@@ -422,10 +421,12 @@ WalReceiverMain(void)
 								LSN_FORMAT_ARGS(startpoint), startpointTLI)));
 			first_stream = false;
 
-			/* Initialize LogstreamResult and buffers for processing messages */
+			/*
+			 * Initialize LogstreamResult and reply buffer for processing
+			 * messages
+			 */
 			LogstreamResult.Write = LogstreamResult.Flush = GetXLogReplayRecPtr(NULL);
 			initStringInfo(&reply_message);
-			initStringInfo(&incoming_message);
 
 			/* Initialize nap wakeup times. */
 			now = GetCurrentTimestamp();
@@ -843,19 +844,19 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
 	TimestampTz sendTime;
 	bool		replyRequested;
 
-	resetStringInfo(&incoming_message);
-
 	switch (type)
 	{
 		case 'w':				/* WAL records */
 			{
-				/* copy message to StringInfo */
+				StringInfoData incoming_message;
+
+				/* set the message in the incoming_message StringInfo */
 				hdrlen = sizeof(int64) + sizeof(int64) + sizeof(int64);
 				if (len < hdrlen)
 					ereport(ERROR,
 							(errcode(ERRCODE_PROTOCOL_VIOLATION),
 							 errmsg_internal("invalid WAL message received from primary")));
-				appendBinaryStringInfo(&incoming_message, buf, hdrlen);
+				initStringInfoFromString(&incoming_message, buf, hdrlen);
 
 				/* read the fields */
 				dataStart = pq_getmsgint64(&incoming_message);
@@ -870,13 +871,15 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
 			}
 		case 'k':				/* Keepalive */
 			{
-				/* copy message to StringInfo */
+				StringInfoData incoming_message;
+
+				/* set the message in the incoming_message StringInfo */
 				hdrlen = sizeof(int64) + sizeof(int64) + sizeof(char);
 				if (len != hdrlen)
 					ereport(ERROR,
 							(errcode(ERRCODE_PROTOCOL_VIOLATION),
 							 errmsg_internal("invalid keepalive message received from primary")));
-				appendBinaryStringInfo(&incoming_message, buf, hdrlen);
+				initStringInfoFromString(&incoming_message, buf, hdrlen);
 
 				/* read the fields */
 				walEnd = pq_getmsgint64(&incoming_message);
-- 
2.37.2

#2Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#1)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

While working on 16fd03e95, I noticed that in each aggregate
deserialization function, in order to "receive" the bytea value that
is the serialized aggregate state, appendBinaryStringInfo is used to
append the bytes of the bytea value onto a temporary StringInfoData.
Using appendBinaryStringInfo seems a bit wasteful here. We could
really just fake up a StringInfoData and point directly to the bytes
of the bytea value.

Perhaps, but ...

The best way I could think of to do this was to invent
initStringInfoFromString() which initialises a StringInfoData and has
the ->data field point directly at the specified buffer. This will
mean that it would be unsafe to do any appendStringInfo* operations on
the resulting StringInfoData as enlargeStringInfo would try to
repalloc the data buffer, which might not even point to a palloc'd
string.

I find this patch horribly dangerous.

It could maybe be okay if we added the capability for StringInfoData
to understand (and enforce) that its "data" buffer is read-only.
However, that'd add overhead to every existing use-case.

I've attached the benchmark results I got after testing how the
modification changed the performance of string_agg_deserialize().
I was hoping this would have a slightly more impressive performance
impact, especially for string_agg() and array_agg() as the aggregate
states of those can be large. However, in the test I ran, there's
only a very slight performance gain. I may just not have found the
best case, however.

I do not think we should even consider this without solid evidence
for *major* performance improvements. As it stands, it's a
quintessential example of a loaded foot-gun, and it seems clear
that making it safe enough to use would add more overhead than
it saves.

regards, tom lane

#3David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#2)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Sun, 12 Feb 2023 at 19:39, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I find this patch horribly dangerous.

I see LogicalRepApplyLoop() does something similar with a
StringInfoData. Maybe it's just scarier having an external function in
stringinfo.c which does this as having it increases the chances of
someone using it for the wrong thing.

It could maybe be okay if we added the capability for StringInfoData
to understand (and enforce) that its "data" buffer is read-only.
However, that'd add overhead to every existing use-case.

I'm not very excited by that. I considered just setting maxlen = -1
in the new function and adding Asserts to check for that in each of
the appendStringInfo* functions. However, since the performance gains
are not so great, I'll probably just drop the whole thing given
there's resistance.

David

#4David Rowley
dgrowleyml@gmail.com
In reply to: David Rowley (#3)
2 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Sun, 12 Feb 2023 at 23:43, David Rowley <dgrowleyml@gmail.com> wrote:

On Sun, 12 Feb 2023 at 19:39, Tom Lane <tgl@sss.pgh.pa.us> wrote:

It could maybe be okay if we added the capability for StringInfoData
to understand (and enforce) that its "data" buffer is read-only.
However, that'd add overhead to every existing use-case.

I'm not very excited by that. I considered just setting maxlen = -1
in the new function and adding Asserts to check for that in each of
the appendStringInfo* functions. However, since the performance gains
are not so great, I'll probably just drop the whole thing given
there's resistance.

I know I said I'd drop this, but I was reminded of it again today. I
ended up adjusting the patch so that it no longer adds a helper
function to stringinfo.c and instead just manually assigns the
StringInfo.data field to point to the bytea's buffer. This follows
what's done in some existing places such as
LogicalParallelApplyLoop(), ReadArrayBinary() and record_recv() to
name a few.

I ran a fresh set of benchmarks on today's master with and without the
patch applied. I used the same benchmark as I did in [1]/messages/by-id/CAApHDvr=e-YOigriSHHm324a40HPqcUhSp6pWWgjz5WwegR=cQ@mail.gmail.com. The average
performance increase from between 0 and 12 workers is about 6.6%.

This seems worthwhile to me. Any objections?

David

[1]: /messages/by-id/CAApHDvr=e-YOigriSHHm324a40HPqcUhSp6pWWgjz5WwegR=cQ@mail.gmail.com

Attachments:

optimize_deserial_bench.pngimage/png; name=optimize_deserial_bench.pngDownload
�PNG


IHDR�dH�-*sRGB���gAMA���a	pHYs�����eciTXtSnipMetadata{"clipPoints":[{"x":0,"y":0},{"x":1444,"y":0},{"x":1444,"y":867},{"x":0,"y":867}]}r����6IDATx^��x����w�l*���PED���`C@��X����c�+�c�^�Q�c/���
�
Jo!=����g6!�M0������������l��w�	D
5,��@�"���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1�����5k��c�=f�W����q��������doH��]���z�)[�l�7�����j�:u�n���O�Q�F����:�Z�n�n�%%�3t�����]�/��c��Ms�7w������eK4v�X���O������^h�5r�kZM>��U�l��q����ZFF����`iii6p�@����������X�B�I/^lK�.�nU���m�����������m�����z��`��y���o��
bi���6|�p�4i��0Z


�A���o����@�I�c��o�y��FA��3,
yC�9���M�2����n����-??���>�J|����'������
�����^���,oHq�������1i�&S �)�����;w�w��E�����n�;�@u����O����6�����Zn5m��N8�������np-g��j+�������4�J�����������C?�]�|���O@�S?�{���]n���:�X��
���Z��G��O���~k]������������q�g{����{����;�����z@Y�U��v��J(���������7�.�����4:�a����[#�TI��
m��v�n����U���f�W!-���;����>i@����n�[m��j�}$+�`�[�z���`��*��@��������{l}���K;��#����ZD~����~�����W��/�lS�Nu�:N9�7|��Q���z����myrssm��6m�4wb����b�,�sq�]w�����Z�h��WD�G~��G�<y�-Y�d}�w��z��i-[�t�=���s���y��!�S5�N�����
)N�K�i����b�
���v�SRR�Y�f��W/7��������%�?O����>��cw���~b���;[�~�*}���k�[�:0��U�>�����'�|r}���w��N>�����M�@�A�����
�<�r�����S��I7��i=Ro�����f����s8v���u����k\\�����k�|�����������O'������wU�}�>}�|o���<�����h�:t�F}�K[_4�����n�����z�Zm��u�w����,�����n��G��[BB��j����eW�<+��9��������|���tU_E�����^��}�v�l�}�u���6�<��k��i�`\�=�vE��1c������ZUz�>}���n��6S����C�v���S����P(����~���+�O[�Nm��v�����9�U���Z�%����u���}��s�������>��c��us�"z{����^Xn`�^m/5�K������4?�Z��k/�=-�_sU��,��hy��cS�����������������G�����e�������J'[���w�}��s=_e��M��`S�������/���~�����Z�4��>���>=NE	�FO�����-*�?������w��(L���c�������a��En�v~TLj�Z;<������!�����1�v���YT�����^p;�
F����{����L�����*������%�)�����i���i'J-J�)�),Q���ie���{��B�hz�/���������?�]�0�k��A���&�y����S���/���(��i'];���
���V4� �1�r�rT����n�G;����ZO9��b�Y���������P+z9h(��3g�}��7n�+\(9/7�v��}�Y�C��F��^�O�W���)�����@V�^Y���������o�a�����,D�?=��j�7�w�c%?O���<�����h^)+n�\_.�u�9��&�o����������W���C�=���.��>@�q��*����g�����vF��M�6��(|���?UU��O�<��u�����_��p}�.\����m@i�8mS4_������>�'�z�[o�����A)��V����-�}��[v~�)�~���m�>��,kYIY���:���a����������>�Z�4���o_��DMm�s��5Do��
��>��#�]!z�z��\�s��D��@��F�u�����jz���A��4����m�(h[_���*�]��:Z������.�y/����m���j�������w����qY���V�Ze�������{��-k�����5J�'e)�Y����&���y|����v"��@����D���{)���2�@���iI�����>�l�M��7l�h��2� lJ��XkF"TT%MA�����v��C��h�L��K/�T�ct��q��We������^�8U=���|P����C;�
55O*� C!hi;�������*;|����D�r����zy4�����^UFW]��VJ�.��8����	��|si'X�v~�^���������{|��7]0���6a�{������U����h}��T���G�k���>
;�z��J���K�N��R�]i�t�F�^�{��Q���O���,O�F��>�,�>��F)��n�fe���<���
)���zR��'Z����������5�|��3�������u��,�<��+�--�C�f����?�D��vH����
�K[f>}vy��>�7��~���uQ��X��w��UE�G�s�V�Bit�~]U���(X�w��I�{�����r��)��3N��Ui������R����*��������\����h�k�i��6`��J��)�BUi<U��F?_4�<=��3�w 5��>���o��:N;F
]U������z����
�[�O�}�'
�h�T�x�������*,V5�*X����G���Ue^2P.9OEVZF~����B?5��Om}z_�?C����<��r��uG��������9r��j�m���;�0�n���W��5�?�x��6��Fkz
��:p���uK�)�S���[Z^z��<+)����"�ct��3��_��{S�����X?�>���7Z�R��������eG�������^�>������*�V�>�}�3��RH�p1�}�`�����b'F�����-;���2U0x���oT���D���������*����9U�����X9�����.��:����9��j|MC�N�OZ�K>�-�����p�hUE��L����]���*S-���_�Z_���X�I�f�s{��������{��U���v�&�o�m�O�Gu�;��u_�OU,�W*��A������U�G�bAm&�.J�L�O�Y�.��R���2�]U����<we�G��Z���s���V)�{�v���gM�����W��s�9�U����U�A��>Uk���G���ij;������~A6x��b�wU�/�����wV���}5O�_������,|z��eU���-����i>i�i^� �*����������>S�*��D?��������0�����B��R��JL�J;1��T��T;J������;E
T�T�*���h��������a�\rI�8U�nn%�vf�������������_����4�>�k^��Ge*�T):d�����?�jS�w���"�����2���*��F�z�>����fkk�*X�C(���������������h�����/XiG���.r0����zMZG�ni����o���<��������������{�4���h��lEYu�_�>[�z���T�s�1���%>-W}>������9���g��l�'�5E��
��e�����a����@O�[}���P���o�v}^4��NX_y�E���/��N)���i���?����k�:��G��'�x���d5wuP��0Z!�\P�U��=��
���*C�t�A��h�\~��� �X���o;���
��>��:�&�5�|K�Pj��L��(�ate)����ZO��5�����4\�����E/7-�����:�m��	�j	����5�RP��z����4-}~���i(d�t���_���;B�D��2T]Sb��%����4���y����|��F
��vt���i[�`�6m;�-�����K�?�4`�h'H;?��CE��*u\���������$M���I��J�8�Y����+��E��T�Ty'�R��i�������=�Ba�e?�����U�T���5���=M�4i}0TUC*0�.�S0$e����(��_��[���C?�����)|Q ��W����?7�*��C_��\�^��g�Pk]�i���N�^���������A��b�]��M�������)\��O�����z_
2�+�*��vS�RQa��N�5�`Li�mW�p\�Ue�jQ�K������Z��{������uJ��z\i�-m��A��v)p��h�@�$-s����oi�.�'���8���6��0[���a����	Z��������-I�-���]ETU]r�i�e�^�z�`��y[��
�����G����h��y�*�/�}U�j]�t���h=���k��;����;KTf�5m�kt�i.H��>���H����uZ���-'������#�l2��~�`R;J��%�s� �����C�T��*�*�j��ME��d]4���-%�����z���R���"�����O;��	�����_�WE�N��M�A�Utu�i��$���j1�l��Z��5-�Z�|���*SAWy�Uy�>*�+ ^���`��~�h:�������;�"
t�W��[�T������G�o:���,�,�7������W_]_��`_�/��W���A&U?VD�^�f����=m����}��������S�o.U�GW��}A���4ja�mEy�.F������0�>����U�V�v���oIZnU��OY���2����+����-�@����\i�Eo;K�(��`��)y`Y=��PU�jkU��m�����]�[�N���)��Y�.U��C��UQ����(���J��e�{R����W�}���B 
�d���&���J*P-�'iy�S���7�p�6%����w�|�;R��T�c�9�E�
'�y��[VhV����k���`G;�U=�VE���e��lj���Q�����aX����_�*��T?{.���:)����WE����(�k:�AZg+
�D;������[*
��E��U9�������>������Z7�^�����>i�����jC�|��(X~���]Q�u�2A�BE��E����)�T�Y}�����F�-��]E�����`O���mFuojj��F�'%%y�6�����8�
�J������J����O�YE����BZ&���.I�?���Ub�@zu��wV��dY4?��uit �6���9t������i�f�����U��i��%`+��	��k��N�UQG��;zgN�Qg�W��a�\���������(|Q�ue./������+��T�=Je)@�[�������o��<H��E���A����G�P����rA��eu��jg\r>U�U6XU]��P�����S^��>�uT�|�����Z���2�kMRX�����"j�PVXZr����5�\S�������n*�m���,�zB��2�����Qe����(�������pI������6�J�h.�m�|�����[m_�#��,��zMzO��:1.������3���n�/pjB,��*�W��=���b��:!������o��~����������H6�B��LUo�9f4�~?E�.
�7�v��T�����s�=.�P�C=�ND����~2��6�M--��N��)S����sUOz������������'VT�]M��Q��JX:@ Z�:1��"��j�V(�c��SUcjg��Gu�W;��?[^@TYz���V��J�TT�XQY4����TQ��V����b��i����~����5_�e�9���m�*����:�������,*���I��./\���Vunjj����S�P��W���O>i��~�]w�u����L����v�'zY��`CEb��U���J'�-������%�6����u�k�9����6>s��"�l�����P���tZ?��j��h�;��#�����g�q���(U�U�o�,z=:K����
m��9>��#h��.���n
\P`���KV��:��O�-�T�R�7R!wY?u��4������];�����H���@N�d�Oh��c�������Ra��V���W��M
�bu@���V]�D/�X���7�n�����{����}��w.���%�j���X�"�6i=��w��m:i��'�\n��&UO�_t��i��"�l���vD��P���z<�F;$��TU�z/����J��t�]x����U���%��g�y�E�z�
���PzSC��T���?Uao�e�}���[����_S!X����Mt���N�'����W�t��'�^�e�Y�*&�beS���������T�
��P����~{}����!C�������(��U���W^��W:@S]�����W�g��C��E]T�<��e���������@u-���v�����������z���8=��S�w�����N��%��wVi�����W]u���?���]��<�[����Q����@���j��jU0�v�*:aVY�C��~e�*�Tm������v?�T�Q:+{���]�Q��NY��5�t�I�:M����W���������vSE���O�n������O�����VXQHW�V-���N�x�g�*)��
]t@�d����XU�lOP��'%{��G�hZ��Qr�X�[
w�����
?�j�P�������E�>Ve�>Y����GP���������_\��n�d���ljj��$}����n��������q}��}��v����a�:u�S=�+�u+�r]���?�}b-��Y5I��u�Y�:��;���.������E����������n@�"�l���v�R��!��e�b'��,������� 4�g����;��v�J�J���6�RJ;���v���>����!jQ��;����TWk�^�+���Y�!�*�7��m�9U ��*��{�d8���;���V��M�u)��Q-a*����RQ�����+���+�6U�$��t~p��C����.]������]	�>����]�At��>����U��m��/�'Z,�����������T��@M-���_����o�]vq����Z������U��5ZN��^���6�������sS�������AlU���wM����wV�h{���
tRQ���5c}@lH�Et��<h�R�5��*8��v
��[�(UH�e��d��J�����u�w�D�'^,�*��($�U%l*I?U���h']��,����Q�����,:X�u�]7�0���Z=Rx�WYQ���(��[���.�;��,����j|��S���u�d���(\�nu�_��>@�:�������[�n��o�
�	�����t��:�UZ�_T����"
]����R������7o��^m��v������@L���8�kuojj��$�Z��P]e�3����]��������v<�A������?�2����������S�9)6G,����N����/��w�iO=�T����P;��y����C 
��m;��m��*x��v�����U5nE����NPyA��?�/�q�N����������"j9���5�������_�~��<���6��tB?�����/��`���"�E����~r�����3gz�T�v�7e9�5�����U��?���@�@U�
+|���/�5h��|�M��lz���a�v�J����4�[Wo|���G�_����u�_oU��@�TD��~1q�m��jH������>�ge�)-���Y���� P�^y�D�_��Oa���o��*
z����b��������_�~����Ajuojr����uD�Oe�B���ER]����r����f-��|O�������m��~�2��C5���;������U$�@|S�_�m�3H�����+�&L��>XS��vSh�<:lRP���h���O>�����R���^Q�^��+z?�U��r�(,,kGQ������u�$Q�vyU�zmz_S�Lq;�������YS5�*'EUXz����<.��D��L�UE�@�
|
�H�����M��B������q����I��!E��B������O?-s��*�������[T$aYm�rW��/��b�gT��?��M�u�D�a���w�y���I��W_}��
@�-���EGt�z���E�O�Ty���i|�A�����<�����������`�F�T�_��U�9�w�}���C���,�������Z��)�nmR���Z�5EU�>=��_y�T���^�p��6}N��Y�(�W���/ j����C���W�v[���+�/����^{��e)kZ�����}�N$���������w����j����9���d��cs�<�3�U?����]����h�]!�B�{����|�J��������%%
"��qU��;wz�B�?���{���?	�NR��=�>���G}�vh��T0��I�|�_zoz�!�_��S�W�O;s~`���wnt�QT�W�k��?����No��(�dp�y������.zhyh����k�����_>�������4�;�������*�}�Q����j�"]�������<��hY����P�=(P��5b����������%E/s��Q ��G�����I�P���h���F��U�u����*�������w'��?��6@�=�P����{��E��~����������j����r�0U,���P���fS��p��t�C�_����0M�ZeT�M��;�X���G�nj��y���Z��1c������?���q��jb;PS���h�o+�~��CA�>��z�y�`]�TU����<�+�l�Vk��w������z8q�D�ltpX�A,�F�@�R�_|i���m}��Y��������<�����T������;�:�<@�������b����}������T���m_���/����0=��c�rLt�0�T�4
��|�I��#�����i4��5j�w���SOu=��i'E�My'�*IA��l�mH�����/,VM��@���Y����v���P��~��S����P������;�XV�����=V�^�Z��G�S��:�X5xM�N���e� B' ����(@Q�����{S������
�t��T8��T���;k����2\�
�V��'�i)0���_���N��P�4zM�����^�u���K�m�����h�*��1�@����r��+o�%/�.}~������C��r*K������[!���#+6k�k{����y�)�������<�n�1��������m��Ve����������7:PUS���^�%�����EoJ�>��Wp_���i���\�J������{STe�z}�?�|�>zO����[g��$��_P���Oa�pIy�3�����A���A���;����V��*;_k�;�����������e��=���������O?���?��jS�m�������B�'�xb�J��h�K�w�^z�k��C�8%{�j�L�����+�h����N+5��F.
�K�k(�s�`��3�t;������H���(�m��Y2�R�_Ea�h{��nY�6�J��)���F�������4X�]t�E�(��/�XW�K]��	'�����*�z�����fO�XQ]�0�,����ee����������o-���?���jz��������'nz���O���`�2�B�3���2�e���C9d�0Zjj;PS�������ze�)j���8d��b��J�kU�
��nU,�;����v����n����JV;�F��N����d-U���2j�;�:�m����<���~]��6a4�s��R���F��Q��~��v��k��	�����S%�.�����F����j��~��*"���SM�.�'�
u��dh�P;j���E��z�W;�
�w�t];j�{�v?��������t��v�������^Ky;Uz����������N�k+�f@�Ka���������o��y� \}-
�~�[V+����jRQ����{�{�����mU��
������5�5t�H�����Z�������U�����.����Z~Z���U��gU��'nS��%����E��n(��0�P ����v=F�E�H���L��T��^se����/%�	
�
�E�P=��JF
�\���Y�������eY����s�v*����_��|���^��h���I�������J�G�J�����\Z_�:��E�K���?�m�����P���q����{o7o�-����Z���-o����@u.���cE����������>���Z��kY��3zt�1���������6������}��sWUU�������������O�K�:�{�I'���%�qi�Tu;����A��>g
������k*�����~�
��\�,�R���2_k�;�2��*��
�����?��wS!��?��|������w����������]���5�3y������� ���4 &�1A 
�	i@L"����*�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@�H!�:6��ea�Z�H
�m�����$�h�E���[�#a�6�5�� ��Dk�"v�k9����
���}�����-���{�!�~�%�V�	v�a��x��DoP�(��D/|�W#a���:�f�]3�F�����	�%��I�5r�w��6������*s�������kl�m�u�{���B��wo�t������oz��������w���*�b�w�f��-��m���'�_��q�v�������n��#�+V��#l��5��M��C��X[��o��96`�;���m��U�P���@�����m���CP���w�y�j��y���s���3gzCP�������O���no���f��
�/��2����-�����D��-��t���5k�}�������*������8�~��g[�hQ���������;���[g�����	
�+�����@��8�����������/??�>��3�{��m����P�|�@�Z�je�^z�{������3�$i�z�S�N��{��)S�l�������w�n�o��7tc��}���]����o����!����_�i��={��W^�*k�[2�����1c��=���m�Q����<{�����SN�������k��+��!���Q�F�����;������ ==��;2w�\���u�E���/�t���������z�-�����4��y��w����������z0���i]�^��uP�ZYt�-����5hV����Q�G}�Xl���YV[�1��:��l��	����4@=��E�s�=](���Q;�|�����Aohqz�1�cw�q�-]����������CX�������1
�tJJ�{�Z�����v�I'�������^��
]���A�n��l�}��m�������u��(T�i�l�c����sg��D�t��)������s!��_mA�zP��/3��
�O<�D������:���;��]t��~���C���4�N5n��]t]&��ZW�}�]4h�[�D����VZ��O?���x����u����[77��^h���F���2����.[�z�[�������^xa��2���~���1
��=����r��6�������x�XA�7�|�Q��q
�UE���;{C�[�d���q��yW���K/��O'B<��s]?���{o}u�B�W_}�]���>��=F��n+p3f���Vw��{��z��v�F���>��c��o�`Q�C��z~U�����1bD�=����+W��q���]w�NQ=222\��(@�j���;���/����~�i����h�oZ&~�iU#+X��������O>i;�������~r��Z�G��~=���~��ZO��F�2?��C�k�:���:����}��>6����OwC��+�������;w�}w��gU�k\����]���(�W���'���4@=��p���*�m�8U����@K�pN��QG��b�V�O�N;�d���__��`Z�������~����z�r��
�K���Q���_�~��Y�f�=�����v�A�0���O�����u)�
U����?�����?����������Om7N;��b�L�@����N�8o�<����@���|\|��v���_���#�p��:�r�J7��0��.p7�_U��u4��:�_�k��\�1j��NMMu�>�u}���.W����u��uv�a����������&M��@V�s����Ms!���*t+���V�_(��X�J��P0��U���?�=�����k�45���5��~����7o��0�mBimIT	�����BU����r#���e-����:X��P��n��?���%i��2Q����Sm��vsar�uU���OU�w���Z�K�.��h��_�A��z��
������w}��h���i$�:)Z��X���������|�����b
��E��P��Z�Z�M�6nXedff�!~������
�u��h�	}��G�POmJ�"��{�q^~~�7f��Zu2EQ�����]�������������K����V�����/�B_�����_\��Nr�����@Z=��7m��Z9e-0�������r�����gjO��j�l�2�K}�o-R�^�{���@��Q��������C�p�=\�\�����`{�]v�����	'���<+0V8Y���g��S�h�<Q=~?�pd�p�����z��U����_�z�}�
�5���/
fubJ��(-����tD-+tJU7�}�Nf�
�����Y����7zi����m�OU�%������������
��G��f�4i��Jk�M��W]u��u�]�5�z6+�~�����F��NFX�����p��X����V�����v�Q���y��'6
EK^Ty����V'5<��3�I3j�t�M�*ZE�>��uIRR�k5��sgw�����������+
��3i�zF���g�m���u�6����]�N��^���~�k������p]�vu�y>VT��	*�S5�����Z}�����w�4z�_};w���}�Q�)�}��\e��#����r�.Ta��j�R�W�Z�����I}�F�r'7T�)t�f���rm_t�2b������4�u�����[��4@=���;��N��Pu�?��n��n���x������t��4�b�7�I�����q��z��l��z-���U����K�,��n���>�
#U�����0��o���������
�U9]Y��+�"_�+y`"##�=�*�K�����P��Zv|��g�Ovm��9���������Zz����|�7���*@@+�S
U���GyT��6����������dv?��7dU����Z4�"::�S�����;���#�����	�|:tp!�*��
�z_���2DU�z>Ua��)@V��:����������YU����JyU����Z��U�:��^�}���Q��eS�Wp-e�{�9W��������uC�r�_?�����w�����u����o��)�LP-t�:o�o��wO��z��n�W_}�����*�u�I���z;���]�`�R�+DH�q��e�%�\�7d����={�<���zi���{����N:���V����d7
�Q�s�����c�q�������ov����k+|?�
��
r-6N;�4��h��o���]K��Pt��~�
�UQ|�Yg�Jd��6h}S��ir�!n�Zn��F�>�w�yn}�T�l�%��'��}��u���7���y��P}��c��s�������o��z}z����{����)���us��?�d����Y'<���]{U������o������N�:�6�	E����9�L+h�8
��~�i�����Y�f��EU��_~�����{�����-Z��T�"V��/����������m���T}��E��_����[�
m_z�%X+�6m��
w*+��:��gU&�\y�������j}��P����=���~��C��*��^����7�wz?�<��{�����5�3���m��z�=����u	@}��l��J���\�8{���������W����r�~hw����~����ko�n��
i@LHb�@`��c��+�a�x�����u����`�=�k@�@i��0��|���Kz�Azr���/h]w �����`���5����l�H^�%~���7��1A�@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	�Y�v��~��v�y�Yvv�7tc��-������u�f�@�v�uW���+l��y����������o��5��
�!�bo������zcU^uO�@:233������9�R����g�i�]w��\�������?��6h� ���o��h�P�F�eGu����k��.�X��]m��	v����m�������{z�#��a�/���?����NoH�T5�������[n��~��W���Om��i6b����?��{�u��&N�h7�|����n6e�Z���6u�T;�����G���{��b�==�H���G��8�Uo����=��>}�k�q��G��_l)))nxRR�k������z�-�����pQ��W_}����oW_}������=fm��q!�v�m��Y�j�wO��{z�@������v�����f����]�Zb����6p�@k���7�HBB�._���������V�B�^�z�a���kg}��qU����HuO�H����4�����~��.�l}�sirrrl����z������j+������1�222�0���VP��qc7,Zjj��n���7s�Loh��{z�@���$�]t�5k��R6��X�t�k�� �4��7�V�Z�*�����az�����tWE]����T4W�� �tPPP����-[Z�
���+���#11�]��==�F 
��@��w5H'-�g�}��s��|�XO�+V��'���q�������{�lP�8c���SN9�n��6����1���8���^i���{���=����V�u��c�]GVV��']�v���w������P(���������{z�
�)�B:''����
{�����/�������g�Y�f�	'��Nl�*e�,q���v�A�������To�
�
f7�t��=�UX������������]�v�������������i�l��v���t7l����N�:����m���nX4�����w��������U�� �t��O�~����j�*oh���?~���*k��UKw�����������kS�L�^�zY�6m��e���@4�:B������z������t��S��_�Gy��<�HH���������v������<y��X�������]�����I7�<�==�F ]G����_�z8�z����cG0`�u�����*������'��������J�1c�����z���zPw�����}"4����+����@ �z[G���@eH�!;���;Y�]w�eM�6��c����_~��������{�����.�w�y��;�8����l���������N@�����]�����'5�
i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@L"����?����f��_���a7�Ij���+h��Zb������<�Y�}?7dyf)�f{�I���'Z��o��e�E��o�����:+b���lU���{��nAw�O�Qo��}�=�i�%&�G�xKO1�zV�VeF��.�v����/w���]�J�-_����[�m����!��px����sb�m���ddG���������M����6�V>��9!����1{��~����W�Q/����e�r,#'b��l;�*
�_�r�-[��NH���-~����'�����vB���O�c���[S���}�v���nxi^��oO���}�'�%Y��]��8l���c��OM����5�i�����e�Fl��q�c�
�}�����C������eEm<d����'��N^�t!U3�jo�A�_m�4S�YR��a]����n�8wQ;���9���@�B\ Px)j����!V�����k��0�XH!rnA�UVG����Y�e�����tI��&�n���S��&i��@�B �za�F;`�����D�j�
���c�M�S�Zxt���>j�������q�XZT
�������o��;�k�3 FQ����9��m�����J�us>~�_�!�z#�������?X8j�W�k�Lr-:�}>���T^�Z4���$��V��U��_�#v��$�����(�D�1���|F��\���Ak�(`?���������W���o�]���>�O�v�>���~v|���Ba������a;m� a4�%*�Q/��<lW��c�)���dw2CQP<���~n��;*��m��z@��F�M����I��m7���|�o��g:%��&�VD���'����;z����/�R��i��F�����;y�^;���%1�\��Zx�zZ��
�����]�8���I	��5�Z5�sU��
�W�1>���:����PH�^IN��DI
,�����_<`��	�J��	��ixA�,\t��2)�~��<{��|�{�x���$���4���
�4�jV�X��P���_
\[�=���:�a����]��O�����Ua��y�5K/J�<�,�����������W�x���d�h�{��F����w��k_�*�����6�Z�l�o!��<lm[���l�-���{��\w������u�M�3d?-YB|�n���!�}�goN����&���&�a�>���r�y�s�g��J	��>W�]\�5PH��P�NJ���|[�6�*�N�5�N������9~Y�'����%aWA�
�=w��sL���6��`���6��<�#��?�.�B��ONv'Z�i@L�C��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@L"���@�3{q�^��o�f�,+�z?

����M�{�]+�����F_<2�rj�#����OK&�@�GB�zK��5F����%a�PH��R��X8�g������/i�[��3�4;'��Ak�����4PC�n��vM��
�0:��'����e��ez�������{�"�E��"��o[������S,�|�7�b���zu��r�-���=�������>v��5i����*�vjg/����[{���k�%:�RO<�tN�����u�mVPP4b�Hn��~1�V���<�h�~�5g����X$+���x�e>����7��S����Zik�����<G(
��#�jH��KK*��0Y���������Z���Z�Y�[���Xp�N�7�k+X0�h�B������������z����S;�����z���8��9��<5��N?�=��;�i3���]7m �����h��rs-�v�%����o��7�,� �����kVYh���P�`�n���Q��X�)gY 5���r�&}S��TH[���y�v�-�����eX�
�?��@ 
���|�P���@\�EV�r����D,�l���\k
_�K7Kh��X�\i.�N��fKhSzeu )��nx> ���pE��d�i�k���>����2G?g��,�p�r��zE;�a	:�q7[B�%����z����h����e�k����P 6��2y��Z1I�2�4K-�d���-?�[vP/[{�
��kkx�����-�.�2��,?��PQ�5K�@
�}�xk�2������[��o[\��r�I�v���zG��z��|��k�QS"�����-��i�v����~7� v���s�8k�RG��m��������>=��w����/kRx=i�-���\`]Fg����|����v�%<���-i�4NX��K�>a��j��Z���Z�Az��B���%<�,����zC�Q$b�������X�q'��!j�i�?Y�q����Z������rs��Da��/Y��/Xr�C-��s]�i�d��e�E,����k��i
,��O����-��q���`���*�>O�Z7�hz�������Y���%�@�#�j���E+��WP�Hw�����g���b+�9��=��e�����d�e���;u�����q�*k������.|��~9�2�������p�{X���Y�g��}��YA����"���@����L�Z��s�x;�����;��f������n�5oa)��h)Gk�����J�de���.���%���g�c�e����{r���q���Gt��Q#,������;v�Fw=d��4oP��Qo�t -Gw�I}��4�	��j�[S�m�W��hU���@}D 
��w��[���n��4,�B ���4 &�1A 
�	i@LHb�@���D
y��z�������w}�w�~����crl���7�tm[���''[zJ�b����?B6��<��,�n�:8������([V^�^�&�>�Z`��"��`��N�v�������j�4�-����}�[���,}S�,#boM���m����,���yf���c�����a;�������)}��S��e=v�[E�m�(`m
�_�����y���5$�v*�b�@��t����6�����d�����Y[�'������m��������Y�
���dz���~���VE���������O���.��o�%�j��������u�.�������6��W}�1U�e����>���	��h�)��ng?/��U��@�#�Pk>�������`T[��f�����9��U��y����n�������V��\����q@�H���D��_
��Vq�O��')�uQ�������#���]��r�������7V�R�
���o:7N
���
�[�j�����;�c��\�edG\�sFN���ky���]�u�>����o���9���j�Q6{j�;��o���}=+jb�@@�����G?X����}T��u����������S�����\@=��<��+��y�����Vq.�>��,����|t�]9&�r���i�R�V �<�b����he�UG�jTz0����L�@��{�o;4���WGlyF��tzJ��9)����`+3#���![X�|C�&����YB|���@lH�)�P���
\�h�U���i���
�dM�=�5��J��N�q��������\u���V�	�b�@@L}=+d�����.������ ���5��������x�������iR�@Y-<�/[��q�4�@ ����N0���I������������oO�w��)s�Zo��"�Z4,�|E
�V[�P��,���|F�=>.���vD��wb))�]��~wfz�bCm#����Cv��9��]��ttR�����Uzb\��99��jp����f��r��o�d=����}Z4�a]��C��0��	������Yv=�$�����*��@�V]�f���WFZ��	����V�@�tK���R��f	��{Ck�����_��\���I�^������YA�+������%����*��=0��o��������_���A;��Doh�k_�qU�j�q�n	vR���
��A �z��i���/j��\oH�$%Y��#�D(
����@-QetM�����s��@�%j�+yS&z���C 
����]����P{�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@��� ���4 &�1A 
�	i@LHb�@�H!�:P���3����O��Y���w-6Z���]�;f/���m���e�U��h�6�v�!I�U��E�2m�u�Z�/��{K������R��Sh�����S���g���@�tK�;���^d��n����/�U���K{C�kx�������-���@������.���z�)oH����k����w����;�<���hc���f��yC����/��'�x���g������j�~�%%%ycn��k����G�XnA�o���1�.�h�7�3+(��i�[d�j���B��X���-����~���[���W_}���Zh�{�m���-o�w���T����v���Z��V_v�RR,�['o�)G�`	�t�n�����]1&��,
{CJ��e��r�����?W��������!�+(|��f=�%��J���E�T��Bv�������:8�������	-;�0;�����m6���l��Y���
�l��Qv�QG�k��f����u���&L�`�{��v�m��� �L����0Z���������'$X��=-����^"ku����h�~�u-Z��Fw<h�'�i���RO���O�f��|��+Ox�WY���K����.��%91`'�	� �������4��i�5H.z�V����sl�����u��3h�����n����-7���|�gY����#��RRR��'�4��vY�n�]p����nw�y�u���{dQu���w��6o��R��GU�:z���v��7�n��fS�L�o������K�:u�v�a��#��{����
l:���)W�����du�hh���%Gb�^��������-��V��{�aN `I������,o�W�#�?�������-�!�#o���=X�Ea������<�^�.��eD����6��d;�_�=qf�
�3�*���RP4b%��&��.[r��-�:N��?����s�96x�`��Q�e�����s�m����iSo������W_}����oW_}������=fm��qa�v�m��Y�j�w�i��gtiH��~��������}����.�����Jj�df��:�y��zE�5if���,�b���U�y�H�R��k��������u�.������Ffn�f��&���������1���6��1���i��������M��t����{������L����|�r����\P����
�4�/vU�p������A�v�\/i��?���
�]�����/���qy��
�+WX���X�SWv��Z�@b���v�8�6�f���?-P�y�y�M[q��3|�a����w[$s�7V����[���\%������uk��F^?i_����n���c]N����{v|�5(|�9&Z�8�{�u���k������+W�%�\b�n��w�
�322\���?������*�w�uW����]ue����6}�t<7n�������[��f���
�Ly�Mp'T��@R�7�r�Z'K,Oh����r-���,a����gPg������
��������D��_
��Vq�O��U.��$l]n��K/:_O�/}�o�����}�L�z���;v��9��>�hW!]��C���/����|���$�WA�u�]gGq�}���n��,]�����U���/(I�;�
ilIR�W�*�~�
��v{�?�&��x�5���������Y�[�������}���~��O?���:A���������H^�YA��
�����i��}�����	���(�h=z��O;�4k���w�:������?�g�}f�g��k������;w�B�����hi���%&&���?A�m�o��&k�n)�eqM+w��h�����6��V[[�\�_ 5�RN8���V�tmQ+��~*��
�O���5��?�����I'F�j{�9�:J�7�z�-w���9KNN���������{���eQ��
i��������U�6ZR��F�o[\����{?oh��o��G+dV?�M�b+H��-�HV�74���Y`�V�]ut�FUO���K�Zu�D�N�����4}���������lw���z��x�
;��c�{�n��1v�)��\`���%'��+����n�o��Z\e�)Oe�������]��{�������k�������
����oo���z%K��_��[���cO����a��z||�E��l�
�Y��E�d��k���#sg��+/�`�=���wnAK[����e����
-R��L[}M�}{�r-=$++����O�����Z'=m���;����+����5���dk�2������V����9�4-`���l�Q'6T��KGe�>�%���X����S�I��f�N��m�-
�_qT��`����{z���B�R�����w���v�qG�W�OE�Z�l��*���)��4P�(���IQp)�������4K�{�&���Bi	��Z�{Yx�r������_)������B:������P����m���_�6�Y|�����-��
-T8���?���Lv��X���_�4h�Z�(���g�l�����%�����{8v���Y���X��Y���3"��k�8-`
�K��jpm:�}����
�/ov�^A;���
�*�� �
Y-7�
��6�������4
���;��s��������M�8�:� ;��l����������^�M7���[�$�[�~w��]�����kE����]��c'y���X�������%�T[s�%�t�A�~��eV8��.��W_d��Zb�},�s7��q��=���5��>4Hw�f�a�/>m�CN[_q-����+������[�;Y����`��������������v��I����o[�4����_�+��o

��|;�p��=�n\
_��F)�� _����� ��2�?���1
����]^����ZRR�k�������_u�����u��[om�:ur'D\�z�7t�����w���kl�]�Bm:�mR��Sut�kc�����F��t4��	K�w��?��=���Sd���_,H�74K+~��`�����',�K���=[����s��s�5�����������\��;�[G/�/����Ez����oW�������KG��0�m�8��q�/$�g�
����zC�F ]��]����
�w�eoh���mk:t�	&��$�c}��������{o��<�Z���������]�tIs���)S���<��@]�2{�	$��m�Z�������
,G\��~�-���/]uy���Y�K�u'$��2�xk��W!]RB�v����X�'�i4{�Skp�e(��5M���~�����P^o�7��NI�^�����B6fB��Y��;$�OLv-;|
S�P�MRV�h�u����m��E��6������}��v��G�����w��}
����j{������Ow��+�j���?�v�a���{l������h�z=�����I�&n8P��_v�%&�=pr�}pu��+�u�8���d��p|����+���AI�8�x�|�>A���4;��DoH���l�_�F��1�:f��6}�tw2��z8G��/��R;��S]���kW�o���E���F�r���st�h=���*�U]�g��v��W��3�G�.���4m=�B�A�ycu�K�6��<�8���t 6������M�6����+UE��3�����n}����S����k�����:�B�.���y�;������~+6=��ii�O��e���^��n�6"~O���wg�w-6�� ���=�k���uIm����� ���4 &�1A 
�	i@�Drs,���m��N��������m��L��"��e������|P?[~����������\gY�����m��eko����i@L��^d��?�2��"�VZb��������16��[�}���K���i?X�Nm-��A���7F�^�<}�e���E��,i�~���w/�
�H!�:P�������2��4�Z�e�{x�b���I������?b+�.���t������q��w�Y\�D����<g�/>c�={[��7[\�F�����{��[x�*K��K����o��w/�-THj\�7_Z��i�r��z��e���B-�����`�����[�FKN��CK��]�*�	���5*��k��>����-�����y�������|�1h��
�<UE�N����lI{��
u�4�FE2�Z���. �����r�kY����,���,�v�7f��_~��&M-��l�/��;�.�.<�
f���*��u�W.�`����k������7s�c����vHjTh��d���)m���Y�N�,y�������|�����j�cZ"Y�^����V��;o�Hv���N������ak�����	/_��/��w-��,���{�@�&���������I@�Hb".��5��qkt�pK��k<|�%r������|��7�i����<=��������
�[$;��F>���T$~����S������i4y�yK����|����0���4 &��zX�cg�V��8H�X���"����Z�����,�o:�uOK�e7+�s�E�����-��!������I��Y�a��Ba��1�
b�@Pk�[l�������<
�TG��,�b�7�j��|��Z��7��4�F�J9�is��p}�h��_ZA�g]�wlc��k��	����`+�.K�v�-�Q+���YA�7�HX���e	;��
�D 
�Qq�������N�bCk�p�r��uqb��E�
%0���~�u������6s~��.,�q�����
g�u���o��%t�ly?N��_�yCG-��zU��,���7�R R���+�����������kE����]��c'y�������-UF���J��y�%v����4sm3�g��`�.����������e����o����w�p�:��~���}/��Q#
�{�R��fiC/r�D��k������Yp������fX��y�<�Pkp�
Hzc�X�BP�67v��6���Os���E,�����n�%������+���th����Zp�.������1���,!X����Q�&��=�Zb����������K��ETH���B�v��
����,����?i����?�^U)`M���U�&�k�
�[f/���m���e�U�WA�$��w����0%�
���%���/j��?��0Z��B��s���������3
�=��u�f���o����u9�E��K�����z�j��C�U��2:����������Gy�-P�H����#V��L���j�+S�x�@}W'�u�����Sm��q�������kXvv�7T��h�Q���kj�MGY��@j-�^�v����K��KOO�=���]����E�5,55�]��z`��@z��v����N;�d'�|���n�������.���������3�p�t�����;w�����M�e	D
y�kT8�?�����
�5k�~��v��'�`�Z������q=n��6~�x{��g������������n�sL��*���L�Zl��>��VdY����h1v�w�n`��������Z���}���c�-_�����''[zJ���/C���<�}q�
�f�I��s���?���<yfc.��&�[��������@��I��>�7�x��`s���w�}�N:�$�f�m�
�u�;�`��~���O���q�Yg�i�c�%��,lg?�m�|�gk��v�>���1���<�N/��_����#�O�;q��m�(`c)�k
���,�8�3�]�;���Af�������
{#P�bHgee����~���ic�@�+�|
�w�}w7�����
�t��"��n�-��������e��2���������P���m��6��$���$�7���W��9��,
�`�<��U/��g3
l��q6��q�1	��5kf>��u��m����4�:�w���
@]�Ya���6��D�/�����[�.b;�����m(��W�n�����%k���V�����x��T{���=j:�����W�y?������	.\.�n���;�����$[�D��.�(�n�����IZ���`��P���@z���6a�w��K�zC�������5��Y�M���e��JrO���z��XW~��NL�����.��m�����=lyj5�^�`�]~��v�e�YNN�6y�d�o��l�}�q����W^��~����UW%=ca���2��m��;���M����Cv��J?Q�S��w��kmZ����R�U#*�[�Z����g'�x��-�p�B������L{���m��i��gO;������^{�}����:[����
;6�>-����NT�o���$l������A��q���mp����"�~��ao��^����@����rm9���J{����Q�F6g�7�o����o�{��go�����w��P(������m��h��1�NlxX�K���0�NXm��q6�{�.��h�M�c�
�OB�����k��Hgee��3����e��[o���]����n�z��V�Z�a��us�;~��W[�n��?�6M��pU��IK�!��`���ya��9>�B�J �����G�m��7n������/����+���/�"KHH���T������7�-E��q�(5`K�F6j����n� `�)��G��7�n{+���Zk�Q�������.]�X������Nf�V
�������RZ������he�>��`}k�P�l�/�[`��M�AX��h����l���<z��_,#'b�������C�Wf~On�:�V���4W��+V�p�t"�����{�a�m��&�g�v}�w�aKII���eP���$�>�Y��{d���Z���l����������l��A[���G�����U�]::�^�6�Z7��z�����<;nx�
���j���V���d����}��W6t�P��������s����>.������_�UW]��Gk|=�-M������d��C��Y�o~�vO��NNv�����%Y�F�zV���*��/����S��y��qUM�P�M� y�0��@D=1jAff��y���������{�q��zF_x��6j��b������L�Zl��������Zl�;��V70�kWm�P?�ZSf����
��3g��/�l���
>|}��v���^�u{���`W�g	�I
u�!C���Y'.�������^j����$o(`KUk-;��F������]u�eG��Y���H��4��YY���h�n��{Y���,�]{o(�m1	�W�ZeW_}��������k����#��Io�yDk��v���W����������@R�5>�P�:"&���+���O��?��Ru�1c�X�f��!��!�]���U����7X��O�[5+����?wx�@m�IiU5�����//vy��Wl��w�3�<�����b�M�>����JKOO�SN9�F�Au4�C�MG��M��]�-&��N^�0Y���e���v�5��UW]eO?������������k����O�;�����5����{F�'�.��j[�$��������Z�n���c���������r�!�����/,#�P���de��K�v�jJ�d���Y���������C����l���-g��f��7F��������,��t���3oL@}S+���u�l��Y��eKKNN���N�k��K�Z^^�7TV$�Hn��5mnI����������,���l���[���,����t�A������jY/=_8��O=������v����=�V[{c��Z	�U���
�sr
wZ��z�j�3g���JjP��\�]c��{X��n��kn)vI���MAr�O���=�X���s�7}z�;u��7_��?~w��G��i%�?d���%a������V�
X�l�������[������#�x{���5l���TVx�
�dgZ\������Fh�<\�w����[�q�X8+�����Z���������-�!��@:>>�N<�D�m����.�3�<�>��[�d��X������N;����Z����s�1��4��HA�Y(lqi
�!��+�I��9�7�H\���n��zC���[��aT�|���ViQ���>hm��qU��V�ZY����_�~�������#F��;��=TEx�2wb���Sm�����u���7_e�%{c���-�\�:����X[x�7�t��Z )�r�{�V3������
��"����b'#;b����~wf�zy������sE���Z�rO�����i���kK�V�?;����=>6��8����i��R~�2�j-����0a���b���w����3���?���~�m�u�]�pPuj�!��������X�Qc�������"������
�o������g����*���}�p:��!�>�Bk� 1a����gPg������
���������Yn�Y����jo�w.~i�����.��/����!�e�x;�g��ig_�*�KFf����+i�!;��l{cR�����N�������P"���@����Xw}�w��*c���I�����_����Kx�j��q�%t������9��',����|���~�unx���,������-�gW�?k��W,7����>X�����-Kh��V0�gv+||�Fn�zJg�s��~=�\x��}��
��#s\�|��doh����\�dz���7�N�t���������o�����Mt���P��Wr,#'bH�C�$]��H�VH���������hQk��cNp�B��p-=$i�~���-n�V�����;�SK�yWK��z���J���o��{>?��@j���p�{�*�cI�6r���6�8^�.b��W��S���������*��~kr������H���F@�Z
�sssm���v�}���W_��F�u9���m��U�#��R8�����-q���n=��s�Z�O'Z�'X��ns���	v���Uu�-�r�^�t}�!�P$biI'�����D\�M�5��Bm��S��l��qv�n�O	��@z��%v���Z��}�����{���>���2/,�p�r}@���U����m���Z${C�,��lw�C��zC7���|���5on�N{xCKW0w��<�2����Ax�����iq-Z>_�6.5i�W!=cQ�?��Z��;����N`��=���>��?���������o��;�k�!�����&+bmZ�������=��>�a�e��)
@�Vk��k���.:���w�mc����?����-��b
T�3a���u;u���fZ����"y�}c�%�-��.e���u����,��I�t�A��v�=�"g�5�:`��������Xh�|oh��qs>��"�2-���P��-�(z}���yz��jo
�6u~���P=�}=�����$���;{D���.�UM�5$�v����B:'���������K�8w����f��c���N��x#@=T+'5����/���L�b����u�����N�V������_���^dk������Yb�},����M�hy������Fw?���B-��WG[x�b����E��,�oK���b��Y�FX��O[���,m�E�Ps=���x��_����[�;Y���p���n��
���k����}�{�u�!�Z7+:�P���s��i�����$7���a���\W9�y�xk�M�M�3l�.
Y��������qZ�m;>�Z`��k-�.���E��edG�����j�k�H�~i��~��
�����K�Z�>}�]�v�PP\�|������.�^��=���$K�w�5~��ba�������?���]�������u�6j�Hoh��@���Q�;[�����.,���l�c�[����r�	���cF�����\FKb������4-`W�]`���~�gW�����������m���v��D��g�F��S�w���5a}-�);�k�����ea�6!P��J ���`���oN=@���jkK��k����b\u;�Yo�
�v���|f��g��~�������2�xk��W!]RB�v������"������58��r{U�Z���5I�f�Dl�����;l�5����+�/��V����y![��i?.��a����ZE 
����@�a�����{���Sm����P��3�v�q_�I���r���n���z��|�cYv�����[|~d������*���
�{0����{B�L^*�2{#;��s���-���hKtr����*�����="UE�|����U+����l��e�=��)��xd���Q`Yy���57��#�m~�	��#�rn�u�-Xv�����Y���"���Bi��:��O������\e����Y�4E�;��P����������B6i����r�s�%����S�'F��Z9�ann�����6s�L6l��^���t�b:t���[{c��Q#;��S�A��`���0�8�[q������]�^V`��`7*:a_}����WrlMv����S�x�an�~Z��
��|P'%|��\w�W��5nB|���m���>��7'��a]��C7������M�������-^��;���G'��P�J �b�
W!���{C*6p�@3f�5k��l�����]����65Q]�If�\Q|��G������J������RY'+��q����0dO���9K���=���b'F�u���:���������g?/YA��qj���`���H
�^��
���oH����m�=�����]���C W������_�j{�P[j%�������]���E 
��8�; &j=�.((�	&���_��D��?~�k����j �h�";���l�}������>����������x��6�|��-U���^�l��{����[o�^{�eg�y�u�������_����&O�lG}�=��S��E�^`��C�v1�k��v�C�IFv���cs���!��W�.���2{��<{sr�w���-�����-=%�
��_��v��[�Y���W�d�vM�n��Z��~��w]}�����q���8`�%z��S�4�,�a����)��.�z�\��n����f�F,�pP����������X��<�P�s�h����l���0@���@:;;�U>�������*KOO��)N�u�����o,''��[������ogw�l��+~��x���uW}�a��{~�DKI,?PVet^A��m����uQ�
���J ���e�����]�Z�V������o��9����8`�,]��|��
*�LVp�@9-)`��eY����
�Z�S	
�E����|�!�P�(d��Zm���`���Rs�#�3�4H&���Z	�����m��6u�T[�x�7�t�_�i|=[�e^���E!�P�;����3���\Q�D��r"�:+b�r#v���W����X�}>���Y�2b�x������=�!�d���s����Z	�����_�~��w��]w�e+W���)N�u������{��2�B�����<=`{��w��S�����rl��
������j�����X����m�8[Rx��ws����1�����K���E�u�A'B��v��9�:�P�M�H!�zL�Z���=�\{����S�Nv�q�Y�^�,Z~~�M�8��7}�tw�SO=eM�4�
l>UL�����W�/����-�N���
������]�=�[��L[s�����4oHqi��c���n�PP`�e9�gI�������l���~�u�~�e/_fg�����S�eI}*��/��,�gD���\0��YQ-D^�������
l�	v��I��O���R���M���:��{��\k���NM��
�~.��?C�g�k��������o����Bv��A;}�D7@��Zi��?���u�Y.t���������}�������_�F�-Q$r!q\�����`Kph�K|���17������G���)�^{��������������������-k�s�#��AU�Gv��%1�l��Ak���+���]��4��n	�2::7��1�:���5Y8��u�8�|~-���+h�A�_��x5��ii���=��3.x���k�
ra������~��E�����5���5��6K���b����{#^��2�{�,)�,!�Z����[��S,��#��S�]�u���Z�������,��w-�|�7v�j��&i[�q��Q8�]�8��/j��)�i�����[W�|^ �j5����8�}���������z�>��c���K/u�u?��*�r�E�3-�yoH�"�����Y����(����I�X 5��j��S��`�N^�a!�����'=�e�>�m���C��\����*iU0�mo���e���%��*�*��k�1cQ��z �nx5���^�N���A����=
5�V����L>|�
6�B�
;���v���~��gc���p��V�-��e�-.��7�by_~f�_���cO������((pAt�57[B�v���l�5l���y-��~�x[�"l?�+21��UG��"n}@��]��D\����"�/���]E��������vl�m���z�O�j����}�xoh��j�sFd����]�4���/Cv��6������?��PR�����h�%/������/�H+�VU�*���w�����1������W_}e�{���p���`�^���v��>�V9���s�!}l��WYh���X��^d�/>m	��n)����VBB�%����)YQZ����2���u�������<���I���wr���sl��|�|t�=�y�5o�{����P�?���
�����y.���9;�g��������q��l�G����&���-?d�1������s��f��qvx���?�������e������/����;�����p�_�}�'��{m�F�K�[v�3����������J�V8��
���j�u@ R��S�>��
:�N<�D����m��v*�i���IUE���v�
7���~k�����/
TU�������kEH�R����ku��v1�kWm�)�=��^i��&X8��pu4H����,u�i����7���~�����-Z��-�Y��y���/��m��Fw?l�[o��U5��������Z��>j	mw��_�5�^l�{�m
�s��*"�2l�MWZh�������~7����sE���,����������S�]8 ��n\<���������S\U��=��Y�
= ������y���6��<�#h���
-�*�'���*���YjR��)|������/T�|��<�=���/
�/�c��E���I�u��y�=��?�u��y�����]U:@p��r���a���dk��P�>�����c�����gO���;�M�6��hQ������C=������,/��O
@�)�^}�P��i����T��s������ ���[��v���~�R�;�B�����?u�.��3]��\�������4K;��Z	��u�8���d���4w�Du�d-�r�������n�����������}����i���q�x{��w�����v�I�.�������ku���q��qn���/�n���`z��M�c�6?d3��2$�@��G�������]�Z�V�����a�l����3fXFF�7l*���
mj��#:l���5��k�HZ�1'�a�\VK��_-���-�WoK>r�7��S���S�����v���<�p��'�NE"��T~ ���q������)�,�f{]NQ��r��,FA��S,..`u�_�RP�Z-Q��+��������M�6��7e�w
%�X\��Z��"YY���QZ���}��-?��km����e��u�rZ���~�7�r����H�zm��w��9�����2�BZ��*:��NXx���J�<j������.��,r`�������y���;���@�U+�tZZ��m����X�`�7�t�/��S����8�yj�MGY���>�^e+�<�V_~�E����HN�;�a|��,��j�j
���%��s,���NH��)GWp�C����dY/�`����3�u����e�����	!�jo
�6u~��~)��.�8�V�n����iw��kmZ����R�U���P��G�
,� b;'pLN�������_?�6m��!���4��-��������;����{��B�:���X�o3�`�oh����������n��Y�c�o��%���YB��Z�*�]8��X8c��]t����'������_?kp������a]�v������)���R��
_�(���`�2"���%ung�>(��0r�q����
{+����*v�{��n��	H RQ�����iW_}�=�����iS;����c����f����>��������{��B�J�?���*E���c���I�����_������_�T-���|�4;dYy���P��qv��I�]��.��"[s��^��{�c�.�\+���_[���Z��v��������{��N���5�2_|�R��fiC/r�r�gw�dq��K=�d�r0?���%v��,�~�����a�lT�5I��''[zJ����Sxb\��99�N�;�N8YY�}�g�|�oW�D�h�Wk�

��
f�\s������Q���k�]y��'l����~�G
�����G����F��?�������+.t��QK��@B�{���~�%�;�?�d�aty�
]�t�A�_Oh�\��_�s�e<p������.Y#GX$��OjYW����/9��)��`?Z��m�5������^>��e���^�*tR���>�U�aY/=�
�;�\�23b�IK�6;%Xzr�~^v'I����#�����i��hC�hlPk���.]j'N�_��b��C����m��V���@u�B�v1�k��v1�k���s]]�vng��O�.�	�j������B�\a�=�[ �x=F��}-��������o1�����},�M;���K��9������]�����~�e���������:�]���k#v��l�3��S�--i���
�/�m�S�*�g����������������Y�+_��[��='&[��������o���~�vl��`�:���e��v��G�jh����Z�"��Jm:j����6fB��P�rs-�v�;�a
����������u���_�@J�5��	kx���z����g-���,�h������[�������,��7,�~7����"=`�loV���y���/f��h��j��3
��� ds�nXoU�2��WE�n���a�����RV�������gZu��:H��������g��'�|���[g�P�~����}����RP�j�MGi�����x�P[T�����-�!�+X0����n{Y������K���;�d�����������[�7?�F�>f����{j��:N�7���;���k^�������9���y��A�N�]T���q����5Y���q'1|��<��p\U:�ng'��P����<;nx�
�h���`/X���'���j5�����|�Z�n��s:��~�mB��������*�g���=`����Z��V�����x��xCJ����_r���vIn)*
���;i�,� �R�vR����m�����!{��<�����jo������-h7J���������m�������Z~4����N�����g�>,�:��B���+W�	�R*�E��t�J�J%�RJ)�����"!��������|��v�����o�x=�_;����F����y�>��7��~����}Wm��VG�S��Q��1��8��i
���#��w����Ki��������K�.�;��C���� ot2B�����f���g�D�=�H��J����Z����H`�n�wv=k��rI���
9%�Mk�x�����d��P�S^��j�3��}C?�>,X��N_w��!2�w��5�����f�[;X#�4�~wx���'D�T�j��(�}J��Y[t<X�n�*����j���U$<<\f��)O<���X�B>��S� o�G��)��d&$�p�8��������Qw�Is��b�$.�P/�"����F�)������o��:u��#�<b&/�Npp��r�-��];��e����[���U�e}Z���X�Oz�\�0{��������=k�S�l�Yb_{A|�5��[G�������H�����m����/�5jX����������}�L� �|��7U��U�Y#"?	�w�K������*��]��c�/t�1��v�w^m����+�&�
�#���T�,i��+�Yx��#������O<gZ}(^	���VFk�tdd�5��������z? /�����M��}����9tv%&�	}+UGH�5������hq��J�#�O��������f&��n�����f:�h2��'�H����#};K�+���#/�gx���Oy����kMx�W���~��p���2k�,IJJ�n�L[{<����a�����m��������.���Y���7|'i�_���	5c���~�qJ�}���'1t��-�tZ��+-M\I��S��v�.A�]�i��{��f�����������z���W�I�r�{�y~NGKRS����<�y��[���u�V��������~*��u�����lB�'�|Rv��%��O7�u�>}d���R�J����y���"��c���zh���*-���T4������]������������#M�l@�����BI��^���1�8�=��������> )�n��+���M�-d�����T�b*{�f�%!�� �C��n�L�q��:��[%d�Pk�t��5��?uB�������8[��{X�z�ItU�s���Y�%�����g�xR~��<�!��-�<&�%��I�?e�����r�e�5��"���7����i��*���e=?�5@�����a|�K�~�"_mN�c�.���U�:d`+�}����m^�!]�R%�4i�\y���d�����e�����_K��me��!&�������&�@~��y�k���	�c_�()?|/A��K���<�Z�Hkx-ii��`�DO����}�Y_';?q�q�D��G#��'>+Y#���*)�~��U$�yKk�����v��l9������qF���\�T�l�xW�S$)U�l�CZ�����d^�U9�ul_�S��(�w�I�j�2���T��#���j�����������'��u)(��"����D'�L^�,S�N>����W'5�U����;WV�X!#G��v��IXX�i�����R�s��S����6
a=!�\e*���^��8�j`��������v����}J��kM�tNt]�Oi��V���4�����F��������D�:�dF>��([N��ng�~
m�r��
oILvI\�KT�������n��Yk�|�!E��dX�yep���9@��,}���
��[S�5����T�}�S�5��w������W�K��@|����D�bx�Wi(:t�W^yEV�Z%����n�:y��wLu4��N��PR~�,���4-���h#��?h&0�G@���vFWr�5��������E��O$��e����}�&F,H��]��"R�L��24��09<�!m��Z��@\:��'������\+�7�N�@?�����7��<���E�y8F�4�>���q:�e����+M�CZ����i���2q�+/Ik�����Jo��G�	s��~<WR��l�Y��+�m.5u��O�<1bAJIs��\.(��x�K"c]��r�����0-8�eGlb���>N��~2�[�4���W�?��~i�mQ�o��>�Ym�;M�z7A�=']���k��~�1E�����(��%}��-�=&��W���8���L/�d��a������P��YZ�n-���7����u�)�$�/�������8�m}x_`�nf2��w?����2�+�^ �����I��Yk��AC�c�B)7�e)������L�v�����e_Yk���U!���4��������:��N`���"e��������+ri#?�$$ s�����,Z%]�b��G�����V$����h���L{�s��J���������e�7y�����J��u���S���R�|�> �G��D�������-��"�
��~�I����2y�d���O����+W��7�=��#;w���	��J+�G��(+�����-6I���1���>�r�M��X����/!��6ci{v��y��;9	`v|�V3��=�=!!|�
f�Cm�a��1��A}-j�����J� �l��&��O�?��5��*�����m����I�:xPkSI]Z-�%�TAg�>E���]�,N�K��*�L��P�=4X�V��E[RM;���r���T��X2���\P�?d��@���?�?�Pz��%��z������={d�����iS��a����_f��%��m���+/�I����>E�R�3�>�>�&
�}*V����o�fO'2�	
5d�	��o�*�1���9/=�����d��`�zK�<{M���+��{>��Yk
�5���_�������\X��P
�g�N�Z}2M��?�%����~5�L��|�C�j�/I).�v��i�������h�@n�H'&&��?�(-[��W_}U��m+>>>�u�V��e�t��I���k����
����l��Ybc����]�u
��?�@�������M��}����9tv%&�3�pzP"��PS��vh�):�"���tD�8�C��S���K"��.1�>n���<��FB��T��~�Pk��iUt���f���]~"�\�/B�w�S��v�F������S����&�z��[�������G������,2�s��P��S����Y���W�1}�uB��ILq�^��=8�+��Nf��H�f��j��f,--M6m�d.7o�\������y����x*�69���m��������.���Y���7|'i�_��& ��9����y�H����3#�?�V�0����8���=���q�	}�W]|�����6I������{��K�'��_`
zW�`���:�h�Kbs����uBC��P'8<�uo�L6m&�{h����4Z�%E6�N����r�q�[
���Y��d��b���c��S�i���>�2����S���'��11}��c����P�y�eGVQQQ���9��#M�4�FK��">����I��1����r��$f����Y��Zke��n�������49��������~����`;�u{kM1c�Wv��oX#�=�C�II����H���J����{��m�6�:u��.|��]r���2|z��%e#����Z%��r!�(�0-��Gb\f}mq��[
�g|�,���"���+wu
4��������]��S�G��9��Q�!U�:d��4�q��DZ��?��"��X������9�N%iV�����������7�R ,5j���{��ji�������kM��Z�j�1u�����v����)z��jgI���I`�N��~���:QR~�^�:w��/�in���\U��8����������0�g_)7�Eq�	��q����w��f���R��)�_��$-Y(���(i�)����r�'e�Fa�>�
���VCN���TS]����
v������+�\���T,+����Th�����@��?-K��L�y�S�����
*�a���o}�,�)��:Br����A���%��4=1?Q���(c?J����������R�`@p.�PC����}G��rC��x]��g���p�A�|�~~��i
�[�j%�/�	&��_~)�<�����H����\��Y�uRC�	/��bd(>|�T������_��J��7?��OD%k��t,����2w�6f�w�TZ�VB���9��N=)��d��h��F�'������^�v����v�&p��Y�����6����V$K�2��d�n��L�����N��t�����R�ne�r��t����2��xye���4_nN�7������y5|���)�`S���o����4������4�����}������#}M�������?����:�������tjV�1=����C+��i�/A����N���$��3�^Koe������_���(��9�uz�'O~�d�6�m	5}e�\�r�cty&Nnz+AVm?y�P48\n�e[<xPF�!}��5"��O�:u�T�RE�?.C���?�8�8PP�C����y��]ZX���_����w������]���*u����{���Zq�g�����
���Z����^k��(
����lZ����i�jW�����+w^ ��g���)�/;�np�H�z~2�k��9r�Z�"��$�U-���N�s���4��J[}��%@:4��"���pi�y��9x��_u��<P.o�s)���%��d`�3���(��|/���Z5�����2�i����~�@����U� Q���������>���n����8(Hjd�4���<�I���W����#�����\�wI{���}�����?@��Z ��]�W_}%k�����?_���k&0T:��#�<b&5���{�R�S+(���@��������.��wy{�k}����J*����R����\(������J����������fB������������J�
����l�7�%�_$u*��n��)�(�U���Y��6�M��%������&�m�����$I������HO�"I���*�:��V��I�h�tS�9���v�_����)��������<�7����������O�������J+�G�_�z�&����`VFZ���UA��%'���=���]{�{��A���LP:y�]!44T �����r�-'�h�A���?/O?�4a4(1�2���h�����C������d����Q������Xn��>�$��_�{����������W���Z����$j����fez�h���t;�O�^��R�b�W`����s
�5P{na�����Lyv�����J���+9��p�Y_CP]w������2�TJ#�~��:���6���Gc]���Eg��]��h�s^���?�S��\�LgT-�0�q��Z��J+��UPv�O:6N?#���.�u���r�]QzF�3�%���������w�nY�+MF��h^�Q��((p���.���[��z��7s�����5pR@�Rv��l��Q������'���V�j�#.������<���RR$��kL���#�$���?�]k����CN�i���^��u��%t��[;��PRe��[C�!�L��}�u;3W'���	���T��W.�AJ*
*g�L�����%ur��h����2AFz]�i�}���������Pi� �>Nq�v�[�������V�k_t�@5��g��r���h������j������Re�{�:��;�Cd�� y��`jG����V��yL�H����V��XnK���d���v79��@���K��_�����dK����X�={��|�����z]�D��Nt��-S&��&���7e;q�|f��b�{����������]�2w}�|�+��+��\T�O���zU�})J�":��'�,�����c�H`����9K�e��n	�;@B��e��*��}r����QQ�=����+�>���r|��~�R~�T�)n����� ����<>?���:�������o�0Ze���c��i2ey���Nu�O�������5���Q���~H1�C�M� 2���a��IR��C��4�Qv��������.?00O�Sft��K�|�$�v���rp���C���[���~�p:��Vz �	������mY�-W���j��d<(�c��(��]��� ��K�uI�[u����?��Y�C>w���']��A�?:���%��2?��������rA��y��&[�
���d��f�����G�����/�3�a�N��r[j������������B���������5h,�]zX�y��*�_~*��0	�����3��������'�h�������\q=b����I�����8������������e�S�h���������J'�{mH��]g��!����2�� T{
�S������V���#@�D�d��	����3L��3��9����Z����x�i�S��<P�oS:���V�g�����}N��&c���h��r���}=s�jy��F�V�]���=����}��B=�B����@:00�LX��^�\��g��x���he�<�MC��JM�����+&Z��[|��Y��^������wp�%&X��������a�Tg<7_Cj��(q�O�r�(J:
B��&Y�o�j0����������'�#}]�s[���+��X�V9	r?��wx���X_�:���M)�mI�����g3?�0����OH�gW]�������L����r��T>�a*|����4y����gL�`�kZ����t��h{�Ja�y�J��n���=���cty&�,7L���RK}����Hk���n��,z�s�������/�3�m:�����5���1�:��_k*����
:��O���>�g���o�����$�[-	�}d�p]>�PR�"�m��6�F���O)���i2���i��5x{mi��}�)O\$�
��/
�W���_�J��W&�)��w?����d`+S���Af���V'��
��T�g���S~��&
��H���>Dm~��i/���Ts0�C�Q�����-��B]�����c��S��z*���/��~��M����~� ���I������-�4�+�69���.��c�[���	�j�5�7:�a�w������V���\8�����Q����������,q��)����;�?m�]�i���!��\I���F�p�$e�9>z���Y���$)��j��=���ymo�������X�(\�|�}�	(�J:c��V��J2��R�p�S~��4��y�3G����?�I��1��� ���}M;�]�; �m��P�J+s�]��|?��N���o����ij���(�L�����o�mh�W��U���>�2����)r�����=&���������_v�����������7��^�2�w�L�>��n_�~.�z�GiB 
%�V'��3E\q�:l�i���K�+����-����g��%I+�J����[���n��}"*I���M��R-5U�fN3AN�9�ya��g��l�Q���+��f�����]������q�.!�� ��+�������_j7����P+i�e��W%�_�d$�a�O����}��k��3���:i_���ME.�W���_G����4�[�G.�c���`�L�6�T��s�w;�L������>���0m=J;+�����J`
G�T��f�|�~�y��XjQ;Z��$������Z��]���:x�);��)2�%�����������8�E����.i�2I^�BBo�S���c��M�������;���7kn��.e�V�����i/�o����o�2��#��5X�}e����k�]�$}��	�s�].I��=I\���l->�J�OzK��}����A��R	�����}gI�{��T������{.���v��)���h(��
�^��Bm�Q!�a�#mQ�����QNs�+���Q
=�g�G��>���o�f�����7�M3�Q;mJ��V�g���Tnv:�/_�����(�F�O�9od�9��A���>��|%���jH;��{���#D^�!H^�.H��3�Lf��g��m�m�����(/-St���Nv�����$��?�M����t�#@)�<%���+���yq|��
��CE?����]��d�X��%���y��N��^\����2����Q&L���g�aIv�S��)��0=����F3K��oI��S�ot���d�M��s�$��Q�:w��jX�E�V�j8�t�<1?�Ts�^�b~N�"I|}2����`N��x%^^Y|�/�U�K�*>����v���m���������Z������V�+�����T��cz��W�&a��4u?NDh�	��k�����T���}����Q��~������ �[�o������2E#���L�I������1THge�;rDD�,^����j��3[���@���:��SZ7����Y'��5���s�u��#&�;�������'S��	�]�	�gi�m8���&��h)3�n�)f����4q9"A����@��G'.�L����GQvy3?y�� ���/���S���I��'�$�E��<2V;�u��5D=�2����������
��[�~�}I��
�����jzu���k�iv�/�S*���uVlK�7�N�P��t���g�D�����[�����;L����m�$h�Z:��2�tb�8��@`��Z8��]���^Ss��Rs�#y�w������k����%���LM}}k�-�P%.������DI�f�8������-=�W}#I��6���B:')[��
��$�F�"���2K��C$��m�Z���{�$�J�v�:�k�RX��,��s�:�s���k7�h��?����c��m�e��P��S�5�N�B�Db�
1��u���
�[�ci��5��*����Y�^v�z ��y�2��xy��$IKS���`i��
u���=�u�g��5 ���8����7Z� ��P����]��?"��;djeP�������1���#	���Y�%�s7k�T���K��]$n���H�E�$���$���u�uf]�n�A�����v��Q�j�����xo��7�@��d���'����uT�'�WB�i�������-����������+1��^!���,�%U�E:��l��{��B���}ifBD=V��by��`3�ai��
���rV�C~��i&���u5�NHq���J�����U>Z����@f��QQQ2l�0����/z�p�4(>v�PIZ�L����h��@O���A(��&i�
I����� >*Z��r����G�O�#$T��{ABo��P����f-����=�X��<J*��{g�yO6"���C���L
��R����#��������_�J{R�$�Z	�W��5��.�
umk���P���@k${9U��g�	2��	
��`���7+�/�g����C�HJ����e��I2su���`�Y������9/�
rR��h�����%��l�#N�S���'K�.=�E���)����_����8��9s�Xk���e��2p�@�g�l����G�?���`�?�x�����f�+�9S���g]����C����%�}gk��������:�.k${�}J��k%����t���^*���lG�
3�K�N��S���'�X&��WH�-w�_������TY����T�������o,��)��y/�J�f����3 �axI�<t@��o�f�n2��Yo�r��g9v�0S�����ym�l��Kv�	xd�P�v��g����VE���=U�[�"���L{��������F��PU����tV{��$�_�R�������O���2w�\9r��/z�NI��~����U������Y��O�>��GI����Y�f�v�Z����<��S����
z{EI��������i�u	@i�<%���+���y��L�d����:�O��SH���T���%-��5�;��R�vk�h�&��ow�RSM�~��Y�r�����_.i'A�]�i	hq��o���K���=��)����J5kM�V�]�n��	6���,�?D�"P���0�-S���#�!�nG��L���CN���J99��-�k�b���q?9�����L��n�$���L(��K/�_��l�����Z;������������M�d��u�j�*��y����S&O�,.��>���@QRm:r���(}��:�N);f�)K`�Nf��~����
�5��o�:��>n�Ng��/�-#�Y&��I��K$��}��=��)K����5-L|���FN����	�{�i��q	��fq�:�����zF@����W���&����L���v����H�K|?Q&/M��_$��s�x�K�6�+5��AD_�l����<�������������{���Q��y���-"u���	&H����:y��]����F[d��T;u;e�;��YG+����2u���L����J[K��_$���_������v��-f��,�����h��2����h�f&�����5h,��>&��[+�}��9M��gT��d��v��t-S2IM�����uu�`�3�>�����7["��i�w�g{�y�	I;��Z����sx��� ~�"���"K��	�;Pz_Xz�O�[���Xy��7���=��{��</���T�������9��#U������Ls��U�V��I����6m������w[�9+��NO{EkO����%��L�v��$��Q���������?{�D^�E�f�a�g��a����!�=��ub��B'�4B�DK��w�ON������	��>��������Y��eJF����������9��g%��W��"��ISI�z�u�)g�F���@�N�;���n;v(��)�C�Os����]��=D:6��8-2�%�����E/{��=:����%ULL����Cj��%��?��>����]�L(x��W�I�N���=~���/��G!!!R�fM����������y�pH��7I���6�����������R~�[������U���������gZ�����S������U�H���%����B:'����[�n{�N9�������y`�|��W�j��m=~"��.3!�V�������Jnq]^��e���q3���d��A��I��^W,��N]%��9�EJ�g'K��O����}7O�a�U�aaR���OiO�Y���������J'[�@��r��}���=��}��</���T���r��A9|��\}�����K�
L8�a|�N�d��q���C�q��!d����rx��V*/��=�I!��J���K`��^����HP�^���f����J��&�o����io�J���=h�>�=�����V�i��^�U������|� k4{�����Y;�������=�\�{�$�Xj����#����F���������RP',�D���QZ��K��t�{�M�O=��[L�z^$o��T�_~�8�N�Gp?~�5�����C�h�S�rkQ����wh��T������{�l	���)#��v�Y����C=���s��j��}�:Y��{��W�l�"K�,1-4tR��M��O<!���7�*
��N�p���U���n���S�:l�i�M��$��'���S���K�����7gI�q/�J����<��<J!��H�G��
sJ�	/K�'��
�?���$���L�{i��e��#sn�b�T��������z�@���������8cc�����9I��]��(A����Y5���)S��k<W�h��������u��������8=������<���x��'��}||�]�v2q�DS�<s�L��(�Rw�n�`E�������#};�m�c(��V,���+$��;M���hUm�E������+'��h--[�	O����j5	�pY���GH�_}��+����M������h�<�~
�3g������b����	�`�:
�K�Lr��n9��r�$q�g�r]�8(�
��z|�D?=V���&���H��#$���&�sO��������'&**���-�N��%�5�\#���3�����������6l��{�Z�@��A����J��e����F������ �J'�d��]q��H���3���SE?9�\?��n����m*�����D�:2�Qi���)'�S�~.s�}fb��h�B\�)����f[�����y�J���PW��r?gr@ ;��wI�w�$�m��s��B%Y�[���f�z�'�Y)��VKP��R���%d�`	�g��i�8������/�-�.O����3f����{.Ok�n�d��9a��.�;Z[yL�:U��Yc��e��I��]���6��u2��t�]��2a��^n
z{�����K�7jIC��=&v�<d��n�.�����X����w������]��������_�>���3����O��-��k�+��Er��[�kE���A�bO�l?*Ii[��&�+�K��������(P�U�\Y�������Z
�����S�����U�Hp�k���������T�"1��q�/����.~�3�O�<��$�[-��}U��g�f��������[I��'��t�;������5oeZz���x����$.�d����:�,���Y�
�L|RR~�(��{�D�z���MH]��g3�Q�v&�/=m���s�R~�U���������x�Hz�zZZ�9k\�*��s8&�?>�I������m&�s��J�O������x���Q�������J����Q���V�0����v��}r�i������+���%y���W�����MNN6�N���j��f19��%�oM������3���3��;&����NIj���<��ODE�;��$��+e{����}���"�����c���a���6��|e���~������YS���[�����_I��_�f���2��#i�J�����b%S��}���.����7e��
i����;�0;�V�Z��K�����ol%������8����oF��C}!i������b=����Q��_�K�/h�6�R��a��j���aF��T_�m}},������3�s�d���zf
�����*�U[q%$H���������o�$����^e��X���st�_��^�Co��S����9��-��+6N����L������8��l��'2���LI��o��J��[KP�����i������xbjE�����*q<`��?��2w�����,+��l�$�{���b��&�Vl����>_zv����=_:����R%���C�Q}�M����V����������Kt���p��)�0Z��e���_�a�>,�\�)�V.�>�t�������_T�Ox�BZ��;��S�/_.o�������D���s��q:t�	����[i����G��u�]gZ�|�����A�_{���MA+���!���y���9��(��u�'�{4��1�O;�S���3u%��b�{���������YK�4n]+|�^��[�$+���th�'c�f��(�NW!��|��7l,��H�lJb��=��	��g!�� �C�2cJ{DG���>��v�ZgK��_�q�&M��S/��4=|Km�r�����o�5�3}�7m��/?�Fr���=��ye*D��+.�sX����'��uK���8/3�!���#������G�%�u���c�����B:�����!�N.ig��>I�,1m�B�����'��U!���J������K�_{�x�+�{7�M�{�WR��{
�
KA�J
�GD���g���2�4��J��5j��\^�d�)G���7�|#+W��.�@�WO?2��C\t�Ef|���f,�?��S6m�d&K�S��5�����������������U&��-s�h	v�9�=v����`��|�V�0Z94����2��M�s��r/L���$i�B�}�EI��O	�w��?�T������wJ�1�NY������C�k��������.�7�*��@�o��\�2��Z�/�%��mpQ�RF���z���$�������r�G��q�����i������_/6}��L���?�P�I:���9v�����x�$�[%e�>#�}Xk-^���2�I�&I��
����������OG���i��HZJ?�|y���zZ����=��]k*�5L�<y�	���_[k�9R���K�={�Y'/
z{EB����.��w������]^��TH[����?3o���:����S������}/((rQ]?��_�U-�EW@vr�P�NN=��o�36F|4���������y�i�S�������e�X����z����IVi����f�_������JU�?��uk�>�c�G�=8V����FK
�s����B��=��X!��*�[~������O������m;X+^�+����A�p��?D�4i"����
*��M�6596n�XL?��K/I����e��-[�< ��m�-Z����o/��53���1c�o�����"##�{��&h�:�3�uF�|/��M)�0Z�&���>�>��?{�D^�E�f�a��������crtH3���$K�����0Z������Y�����V�L��U��{�h= m������I�7K�����*��*��������-%�{o	����1S|��K��������+���Z�!��?,;w�4m)J3�'���3�2���>3�t�R�S������e��k����}��0@v��!�7o6U������;1�g^���(����������������2E��P�������I���%��K�[Qr; ��a����!�=��
���%O-S�z�\?�eJ�6'�=��)�V;��������2L�ZDx�e�����*7�p����Of���w��YS&N�(������p��w������]��b�{���?-;�K�������iw���R�m�����E���L9�2B{������n&����h]�y���a���U���t�F�
�S~�$�^x�D�G��/K���R�����Ysk�h�Zc+m��W/F+�+�z�jS���o�>�O���+�V������C���������yR��oN�_��h��k3����\y	���D������*O-S�Ko�RP-S�4��(IZ�"S��3��$o�N|�W0mT������f���{�����.6l�#G�����;��h�Nv-S�z���/��Y����[$a���2:j�-�<���\w�	����Z
���]y�����O���"""r]4���iUP��d��$��)��� �>/��m3�$��*���2aRn��|�@I;�_b��,��}$>����%�Gk���+	��:y^���%((�%��#�K���R�}��I�m�cJ(jN�Li���Y~[�8B�H�;���y��cT\�V�'���.v����*Z�H���J���M���8{'����>E�R���>�>���J  C�1���i�$)�(����f]*|��H�.�"����l��)�����W���#�j����K9����n���Z�ik�.�@����>cv�zL�u)��.-�K���6���w������]�������e�����F���*u����{���Zq��[�C�X\���J�W��5Zt��_����O[�h��(��)eE.��'�Z�K���� w^y�����A�I�>}L���
���C���;f�<��km�F�{�$�\V�a�r���m�c�c(:��
�(�J����g�6U�yU�\9�����L�2���P!�]��b�{���������O��u���3������	�����S&c�6o������]�$������������I^y�j�|�m��C=��E�'��3�m:���i�u	@Q@o��B���&P
F���h�EGa��9�p�ietRj�?��X8��z��/��36
r��b��6���@Z{F��3G��
���nS�
ET�{�E�-�����,\�P�7onzG'$$X����3g��K.��lS�
@Q��=j/���LO��\���l����@�C��wQ�^��H�-[V�O�.�]w��q���eK�8q����[���9HMM�m����q���s��#F�W\!��M3��(�����C�����>E�����1Rwn�FvW��w������thh�<����r�J�W�����n��R�N����e��	������u��:6p�@�R��	�{�1i����^�Z��/aaa��(��?xO\I�_�����,��
����I
�\x������?� 7�t������y���G�~��I�����u���>2�������_~1-?�6mj�@q���Z�R�K����@�ck ����c��3f���-�6m��_]|�A����������o������O��~y�������3��8)�69��U^Ow����d��[Z�J/Y�D�������[n�f��I@@��6����`i�-�@����w���D�� ���(��H��f����H�M��cw����
e�I�HR���A(
�#�%Z���+)��Vx�1��9#�%Z��k�K�/y�z� ;��D+�69��8=�������H����%N��@q�A%=�����������={�������kKXX�4���			f|����dC�'��f�������}�S�~��i��%�-�:��I�d����-����e��}2t�P=z�	�P��l���7�C���P?��������?l.k�VJk�����<���i����z�j����.��wQ�~*��Z=�|��{����[r��7K�������Z������-[��/�,*T�����i(�P?�W���h��e�t������i����o�^v��!qqq�(mT���+�tjj����HDD�X��������s��i����2k��������HLL�C����~���+�t�2e�Q�F�d���a�5z*�5�h�"Y�|�Y_�(��H�������������#e������`��N�LO�:UF�a&5���w�I��Wi��Iy�������2x�`�OZ��7J�v��\�rr���KJJ�L�0A�7on�Py-�v8r��W��e�d���G�:z�����o�r�^�d���2h� �>���Z �4d���e��yr��A��o��Z�Jv��-111&����K	���j �Qpp��)��:�>�l&0����tjj�DEEIddd����t:�{���III2e��W��T�PA*V����}�5�O^�?��c���;d���R�V-����t��5��F���Sd:���+	�NX�d��V��|��gf�e������i��Ixx��@q��@:99Y:$={�4��T>@���$8  @*W�,����p8�Q@I��@�L�2��ysY�~����_�(�$�J �U��_�4k�L~�a��s��\.�V@I��������={�~��R�\9i���t��-�e��ae�P�x-�^�v����K~��'s=&&FV�^-K�.�v��o�8�N�.���J ���,�����{�����.6l�#G�����;W����-���Z
�m�6���+�����-Z��-F��x���y%��`���O*W�,AAA�(�$�J j&2��qqq�(�$�J  C�1���i�$))��PRy%�v:�R�F
y��ge���r������>*��O��+Wf��_����1��QQQ2h� ��������a���p�����c�l�'�xBbcc�-��������o_S!��E����'��e����n�Mz��</���P<y%��>��:�����E/{�GFF�y��P<�H{&1��L���+�y��P<��`[���Y�x�Y����������/�x*����r��qzH@1��@Z')�����v�m���`�fOo����������4cE�B:99Ybcc�k����@:%%E&N�(��u3��d����/t���O�g��l�R���#�k����k�����@��������o�,]�TV�X!G���{������XN����.
4�k��V����-��Zv4i�D��['G���;wJ������n��������hp����J����-�#�i��!��������}��r�Yg����.~~~�V��W&5��y��i2n�8	

�F%�Wi@�C 
��4��[HlA 
��W���H1b�,Z�H����Q@I��
��;w���_.5k�����K��]+��������+�txx�L�4I��'�*U��_]��m+���3c�w���i�
(	�H���H�F���G�_�U���{���{�m�=����[W:t� o���:t���7�Oj���'_|����K�c�Y�z��t�M�u�V>|�T�RE���
�M@1��@:�����c����~Y�j�t��M���������������rY�E*�VZ�t�R:t����W�,Yb�/���U�����+��eK��#&&��(��D ��� +W���o��TAkU��Y��������{N���O������H�^�d��	��k�IZZ��@Q��@:99Y��Y#w�u�T�^]:v�(��������	��g���e��QR�vmq8f�S��<����Jz���mmP�y%�����~��I�v����_���4h�i����u��&M��	�S�lY)_��u
Px%�v:����*�;w�9s����{������]�Jpp��V�|�A?~�	�E�W�2e����c��>�k��V����[�&""�����5___kP�y�BZ'-���������d^	����e��=r�y�I���Q@I��@:((H�U�&����DkP�y%�

�[o�Uv��-&L0m;�����J +[�l�V�Z�/� 5k�4�^r�%��[�l�a��ITT��@q��@:))I,X S�N�F��_�^�.]��B5o^	����e���r���</���P<y%����1�rDDD�]_�(��T�����O4�9���z �g������v��&�
2�tBB��>}��9
(��H�\.Y�h�t��A&M�${���nI���l&2:t��=�����k��������6��
Z+�5|��j�x@��icn_�z�u�8�J ���������w�[o�%7�|�T�\Y|}}�5��0i�������R�BY�x���O^	����e��-��[7:��A���}{��c����Y����+�tjj����HDD�X��������s��i����2k��������HLL�C����~���+�t�2e�Q�F�d���a�5z*�5�h�"Y�|�Y_�(��H�������������#e������`��N�LO�:UF�a&5���w�I��Wi��Iy�������2x�`�OZ��7J�v��\�rr���KJJ�L�0A�7on�Py-�v8r��W��e�d���G�:z�����o�r�^�d���2h� �>���Z �4d���e��yr��A��o��Z�Jv��-111&����K	���j �Qpp��)��:�>�l&0�������+�tdd�t������������S����P��t��Qj��!>>t@q���7""B/^,.�+�%>>^8 3f��j��I�=d��)nmP���c���J�*r�M7����*����|����������������}���h�"IHH�F�M�����$$$D���cZy��"H;vL���L3�!_E6�MMM����K^z�%Y�|�\x��R�lY�V@q��@:22R�w�.�#����_j��%/����l�R
$�����M���Q�B����d��i��Q#kPy%�����������u�J�3fH�&M�{�+f	��@`��QQQ2l�0����Zt�-@���@��t��}�d����i�m��E��&5����d��9R�B���d��
r��10������;e���&O>��8p@�9�i�;w����[[e^�!�|�r����d��Q2}�ti����+WN�K�z�L���o����.���7Av�E�h�`@q��47!!A>�������z�����g�����={�������E�����Wim��g��\��Y��0�����P<y%���h�
}��!ILL�F��}����^k8
(��H�)SF5j$�~����5KRSS�[2KJJ�w�}���n�����x�J ���+���-[��w�-7�p�,^�X���o���4?5������3�����kLOi@���@Z�s�92i�$i�����;Wz��!5j���+������%K���W^)����T�R��g��r����~����_6lhx��=p�@Y�b�8�Nk���N�j��i����	��JGOW�l�����?��Z�3��@Z]r�%�v�ZHkt�
��\ C���K���j��e�K2
�?��Ci������Kf�k��R�~}�����S�N2v�X���3�y$''����n]�����L�J����o���y����/O=��)����*44���<o����?������;r�e�I``��f���/���W'{���/d��m�B����������7�0a�,X���G�����o��n�Z���c�_�E��h�s^�_�^�qi���l��I��['�V����7K��=e����p�Bkm�;��H���_�v#G���/�\||��m�q����5����1�������)u���
*X�gF�q��7O���+�F�2Iz��S����W7�DEEY�@�H���r��Q��D+�5��J��h(|��!������#�c����X�g����*�C���U+k��z��I�6mL�����Q��" ((H��gZ�h���^�������a�VLk�g���K�.&��I�}�YSA�W���7�C4x._��5z��5k�4�����@��>���/��;wJ�-N��:��T�9s�\w�u�z�c��&�~�����+��~���s:Z}��������F3�*mE�4��"�.tR�W_}U5j$���___3{"��!=~��7�k�.=z�l���LR��8N���:<<\�e((����������o7���o�)�
:�cZ��|�A3	�o�a�����e����{���o�-��r�uK����#�_��@q����hfyY'7y�����%
�K���-s����n]��_�M�.
��b�{�������������}�e�������]��b�{����w����s����������ys�RfTHQz�`���r�M7�0z��I2p��LV�TI�}�]�;:k���-+]�v5���G3y"x�EPjj��D��������'�5�\#>>�?~�v�Zi���>�������-�Z�l�	����N��i
���Bz��	f�����8��=�j]Jw�K��=*-���T4������]��b�{����e-���u����y�g���.��w�����������������?c�ti����B�����3=��b*����o�t�F�$��K:'iii�����u�V III�hf���5k�4? ����TP{Bk��V*/X�@:t���MGF�������+����hf�����Y�zu	

2�sR�Z5i�������c��I����s�Y�aC{��(�����=z�L�2E 3f�8m�[�n]�;Z�rh����d�������K.�1���Z��\t�E�r�JY�~�5z���)�6m�V�ZI�:u�Q��"B��Y�fI�>}L����:��%g
4�+���TA�3�D;
�a��Q���/��o�QZ�nm��3����k��%'N��7���n[C�������p3yE ]9rDf��iZb|��g�RY���[�w�.����~~~~r�=�����M���Y3i���Y���on�����4���_�������Z�l)<��l��MZ�ha�l��n[CC��}�Zk@�H{���-[�X��G'>�6m�|�����M��y�Y����m�N^i�}�w�`\[����#��4�
�<[+��t��ys���M{��-�/�����������X�h�DGG�E/������_�����9+������7�TS�n{��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA 
��4��[HlA ]8�NY�b�8P"""�l����G�?�$%%Yk�]Ao�t1���&�f��>}��G}$����f�����k�����SOI\\��������@��[�~�<�����qc��i��[�NV�Z%�7o��={����e������W���bL�g��7O���+�F�����[����SG&L� ��W7�DEEY�����Hc0U�:t�V�ZY�'��WO��ic��w��m�����Hc����_~�������FO
		��5k���o�n�����Hc����	???k43m���R�\������1
�Uxx����EAo2r����(f���#�_�<��S2v�Xk4����Q����E]d]��r���.���'�Z��-*o�����������]��b�{�������r��u��^�������]�����w���.���O���y�o��Q�S�	��1����Zk��=R�g]J����?�"R���:���������.��w������]��b�{���������.���H�@��-��]���?,���___���<��	�z�)��@F����@����>|X������<���Y���MAo2"�.��U�&M�4�]�v��c����t���;w��6lh�����HcU�V5=�W�\)����FO���?e��M��U+�S��5����dD ]�����V�Z2q�D�(��\[k�3F~��7����$<<������1�a1���*o���	����V/��������u�%44���Hdd�\w�u�d�Y�f��i������yA ]8�N���oe��)���_KJJ�	��*�z�2���H��n��@`zHlA 
��4��[HlA 
��4P�>,�>��\x���p8�a��r�����={�5`���Ty��G�{��i����\.������]_����������+��tZk�������)S�C�f���][�*[�l1��������*��5����EaHKK�1c���}N�m��&			�=P��=F�k�=G�{t�����������k����v��S^�9-�����u���J)[����]�t��s���m���$����=z���������Y<7�'��u��gi�����3����������������m��H�"��Ji�����r�M7��?,G�5D�K/�$}���u����(|�G��7����'[#(LD|�����m[�zW]�v�����G}$�:u��c��?�(4�?w�q����/��cG�V��L�>]��k'�������=�w�����i��Y#(L����s�N����w
���F�s*T�`>%&&���~������r������u
E��>���������s�5���'���ke����2x����a��I���e���f�7m�T���k>��~��0z�������gz�����O�>��o�������~Fz���[\���=��������l�9��E�]vY�������x�]w��%��'�x�\W�/c���~�����+]�2�(<������G��B�n����9b����e�W�F�\�j�r}�����43�t:]����e�����={�G�JIIq�3����o������_���7�q��+W�}������k����-({��q�n������:v��5
����v�����f����bcc]�?���=2d��{y���������5���|�r�9_����\��_����������_>1�����O��]][�n=���;��a���,?�����k~7z��i�N+}2~6�����<��u��g��|;sy�����}�����-�?���;�m%�@!��D=IO�9r�����@���e�����������8
��\�l�t����S�req�nEa�*=�����/�\||����iI_|�<��S��X�d������Pp������/����T?x^����G����k~?P��"b��I�m�V��������>��s�L�2�(��������9eU+���ic�{Thh��}������O����q=�������J��U�em�������Q���\��_�����k������c��8
���O�F�L���#���J�*���={�4gp�>��������(S	��{�1�U�����@+E���g*�qz�}���V�j����w��qf������Y�r��n��A�}������>������?7��Ji���i����[7	�F�����q�f�INN6�Q#���CIDAT�6l�`�Dl���|�u���nEa�S��e�
�]����C�>���_4�}���Yg�e���	���AJJ�����X_}�U��y��i������
�������@H?ik�K.��=I?}��'�j�*�&�H��{�~6�>���7�nAA��4�HU�R���HCQ
��9b��`����o���Y�s��U+�{�-q���=K�����z� �.��|o��i�8p�En�����'�|R�{�93������;�[�_��5����_��������;������g.�����@(�����\����D��l��mT����s���_5G.u���� 7n����q������x�
�N���g��3�<c~2��T�w�4���7�Q8�RK{�i���
���>���/Z	����:�'�C��{������U�^zF���3e���kv����g������:a��e�z�w�5j���x�S��x���������6��n�j~����{����XK�.gw�����[W���;3N/����_�h��{����;p�t�k���}���@�~���I��)��H�@�6=����)��X��9:�G���
�������Y�AQ�_��/_n�-ZH����[P�t���bz���:yL�^��[Q4����\s�������K?��k]�?��r�]wIHH��`O��D�W_}���F��*8�������s@@��D���7��Z��.��C��r�
������*S����.4U�N��T~��R�tU��I%Q�<����<������O
�sZ����Yz0F?���>� TC:�Y}�S���<��UD���MQ�7�3���7�|c���~i�7#�h�~���@��2���z�����*-N�/|z����Z��_�5 �:uj���`h��k����34���(x���S�u�����5�C���h �=��r�����R��g u��a����9�U+��������e�����$��b�
s:�����Q����| �[�65���:`��=U^�����0���~�o�>k�$��7n4���
m���b}������/�`���zkiA 
���u���V�%@+u�4ib����_�4��B�
2m�4S%G T8������Y�f��=�W��������>H{�z�A�	&��
���%
��,���6l�9�U�h8����V�/]�T��/���f]}��={������98f}�1c���Y��������a��N�%A���:������2�g�]��V��F���7�x����
:�XiA 
(t�-^�Xn��&s:��I�L������94�B<��|���rQ�Q����V��z���"������D{���??���������}����(
����9X+q�KV����u��q������^��P���m���i�.m����0}��I>=d�������#F���Z�BA���|�;zP�q��f�C}���Z{�z��h+'���-Z�5j�(�Y�g����+����W	��B�����H:i�������J2=}������������E@���t��(�@H�,�)a��X��Qp4`��A'��V��+z��gR+O{	����O�!�N�����,��R��4
����*]=��U���.|����9���N6��
�N���{L����0
�:s��1�Hk���ura���	���A��`�n�=�;r�w�t��L�V��)�lX[)����
�4P����)z�EK{YfG'2��ZurC� ������n��!�K�~I4h��y���h ��zG{�^����!���g�j,���e���C��K3
�V)�6[9YO����l���^���y���s�9��sgk�I?�����.�(�J7
�:t�`.o�����D���o���e����l�������	�Ui��3���~�s��gBb�����J�����{�l���������!
�~	�����COVz���z��3#4P�hE��6��!u���L��_�4�@��2e�\r�%&���~�r��G����������`OOQc����-�4��	<�����}O�������Z���A}N�u��
�pi�~�l��)�[�gQ:�N����RW�V�Lz��wc�����]��@�����d��(�����o��,-�I������H�D{'�]=UR��f���\��\n��-�������G�6�������0��}�C�~����GiP�=-�=���`5o�������?�\�w�n;�XR���%
����o>��k\_�Y���C���+s�v�f��Q���;�|���]K����]�G�h5�o:�'
��M���9��d���� &
��={��+��=z��Q���a������8 i/���Z�2=��+����_��~0gT�Z�J��p��7��-��|��w���~�@!i�����DO����)�����'O�l&��D@I�p�B3���m�Z/��!y�~��Y��~Y��um)��Q�^�$_|������'�|2����ioo��^��)x$�������F'��T��s���>7���(��=�eg'�C�|�����= ��g���;�s����
���S'�����|��A���Z���[i�h/����T���W��)�yn{�1s����0�J�����t"C�p�����R���;v��v����\�j�ru������e�7m����w�Yk��/�f�w���u��k�����{w�:?��sQx�����k�s�
\;vt�j����<x����C���C||�k����}H����{��3���Rl������'�x����}���>z}���Xk�0x�ot�Y�������q��aaa�v�����]@������~k����m�6W��-���|����N<o���+%%�Z%/���������������'O��s�����SO=e����������{����������H(DZ��~C�g�yF�_��)JJ'��~���(i<=+�]Zy����Qx���j-mU��)�-2�Cg�J����'����������q���W(���2v�X��`���f��s����D�Z%���o(8��������ma��k[_��Z�J���7��Z���	V�^-�����FA�v@z�^��_Z�x�-��}������;���VB���'~7<��3�w��s�G'��v48�CSi�2��
i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� ���@`i�-�� �����W:v�(�������=��I���p�e��e����{�=��}��'����h���������E/��"����+�\ ;w���~���,&&F~��'����
��rY�N�z����r���%  �\
�4P�hh��Asy��-���f.g��������o����eK�^tt�u�I���_~�E�9�i���5
i�������Z�j�J:66�=ICf�m��A��ukY�v�����������K�n�*M�6�Z�jY�@�!��
�5D����e����h:m���?���?�|��C���i���I��o7���e���F����v ���4l������z}��=�Z'���Y�fr�m�������3����K����q>���]�����u��[�%%%�����G�����^�1�-#�M��i�j�����[���Z����g���4��+d���a��^x��?���(|�@1n�Hk%��}���tG�1��5�����gZqhKKHH��:\+m����JMM��_��/������H��]�mz]�>� ���;v���#G��m�L}��!�o���_�a�L�|��2e����K�[E>,��
�����
o
��2����7cz���������K���/mUf����^:u�$�/�s�=��������c�w���N	��A 
3���&0VY+����Xk����Z�k
�=4��*hm�Q�~}kT��o��1c��� _|�����%KL�<o�<��=Z���;�'i������Z���?�
���Z�Jn��f	

�W_}5S����=����5�����Y_�mZ�����^~�e�g���5�^�f��7��w�^�L���3�O�>��[���_���	������Ry
��E 
C:�������X�b�`��E�SCi]Od�`���w�	a���r��f,..N���k�����J��=��'�+�����Gy��W�������C�1�����N�?#
��n.O�:U��oo.{��������������R�J�-b.k�V4���&h�J{gW�^�\��^�c���}���Z9�(7�x�i���<f7�#
�4PU�Z�T#k����G���<k[���>��i+m]�6l�p�����VR�1m����:t��;���t[��B���rZ�cd���U�T��eO+�G�%����b��K/�n9I������;����4@�
q
�5��HC��u�Z�N�Jl��^�`������C����J�}��L�7
�4Pe�|��e��z���b��fLiP�!����M�pZZ�l�������C'��X��s�����5��� ��:#}������z��W�`\Ct��d��6��������[��G}d��X���������q����u�hu���kU�������(|�@1����39���;w�4�fLiE�����V������$�hk�����FDD�
f�r�m����rC���+��?���:����[��:9av������>��|�����Z�-:��w�!�k�6U��g7Y#
�4PLy*�w��ezk0�m<4|�H�X����Z�\���������V��
���ZG�c����3f�0}�o��V3	�o��ibB��b.��& �m;v�Y7/�_�UW]%��/7��Nj8b���Z�z�:�L���C 
S��g
Qw��m*�s�z����Bi]_�i����������D�ZE�
r��Z{-�+W����
��k?g��P+��y�3���V`��Q�\�����A�x��������6l�0�o6o�l���@ 
S��g
���Yc�Bk�������Zo��g�	�������z��f{+W�4��Yi8����Z�p
��T�z�����2�?4>x��u�H�6mLx��7��j�����n�K.��������'��?��k�$�����(\�@1v�y�Ill���;���Zu������`
����������0���P4h�	h��/_~���������O?��	�l�3��F�\��n��>�L�{�=3����[[kh(���5D��0��������Twg��17:���'N���9S�����*_}�������`H���g�m&1�	������������CCk���p:���:u�	&��z��e�n���@w���f2@�P���JnO��_��D�t?���2`��kx��}{�����Q�Fr�=��0]��:!a^��WK���:\���i���V?����Y3�(�@1�}�5\V�k�����j��Ek43???���;M[��#GJ||���V����\sM�U�gB���x{��5����ZU�REf��)���3-<�����P��<��3fB
��JC��{L-Zd�u}������[n1�������8\�5KP!
��4��J
����i���LIEND�B`�
v1-0001-Optimize-various-aggregate-deserialization-functi.patchapplication/octet-stream; name=v1-0001-Optimize-various-aggregate-deserialization-functi.patchDownload
From 7fc60dc245804a353df4ba1e2ccd96f7d0237eae Mon Sep 17 00:00:00 2001
From: David Rowley <dgrowley@gmail.com>
Date: Sat, 11 Feb 2023 10:05:32 +1300
Subject: [PATCH v1] Optimize various aggregate deserialization functions

The serialized representation of an internal aggregate state is a bytea
value.  In each deserial function, in order to "receive" the bytea value
we appended it onto a short-lived StringInfoData using
appendBinaryStringInfo.  This was a little wasteful as it meant having to
palloc memory, copy a (possibly long) series of bytes then later pfree
that memory.  Instead of doing to this extra trouble, we can just fake up
a StringInfoData and point the data directly at the bytea's payload.  This
should help increase the performance of internal aggregate
deserialization.

Discussion: https://postgr.es/m/CAApHDvr=e-YOigriSHHm324a40HPqcUhSp6pWWgjz5WwegR=cQ@mail.gmail.com
---
 src/backend/utils/adt/array_userfuncs.c | 24 ++++++-------
 src/backend/utils/adt/numeric.c         | 48 ++++++++++++-------------
 src/backend/utils/adt/varlena.c         | 12 +++----
 3 files changed, 42 insertions(+), 42 deletions(-)

diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 5c4fdcfba4..7f87df45df 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -723,12 +723,13 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -825,7 +826,6 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	}
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
@@ -1134,12 +1134,13 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -1197,7 +1198,6 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	memcpy(result->lbs, temp, sizeof(result->lbs));
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 3c3184f15b..f4b885005f 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5190,12 +5190,13 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5222,7 +5223,6 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5306,12 +5306,13 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5342,7 +5343,6 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5677,12 +5677,13 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5706,7 +5707,6 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5868,12 +5868,13 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5889,7 +5890,6 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 72e1e24fe0..1aff04fa77 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -5289,12 +5289,13 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
+	 * the serialized aggregate state value.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	buf.data = VARDATA_ANY(sstate);
+	buf.len = VARSIZE_ANY_EXHDR(sstate);
+	buf.maxlen = 0;
+	buf.cursor = 0;
 
 	result = makeStringAggState(fcinfo);
 
@@ -5307,7 +5308,6 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	appendBinaryStringInfo(result, data, datalen);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
-- 
2.40.1.windows.1

#5Michael Paquier
michael@paquier.xyz
In reply to: David Rowley (#4)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Tue, Oct 03, 2023 at 06:02:10PM +1300, David Rowley wrote:

I know I said I'd drop this, but I was reminded of it again today. I
ended up adjusting the patch so that it no longer adds a helper
function to stringinfo.c and instead just manually assigns the
StringInfo.data field to point to the bytea's buffer. This follows
what's done in some existing places such as
LogicalParallelApplyLoop(), ReadArrayBinary() and record_recv() to
name a few.

I ran a fresh set of benchmarks on today's master with and without the
patch applied. I used the same benchmark as I did in [1]. The average
performance increase from between 0 and 12 workers is about 6.6%.

This seems worthwhile to me. Any objections?

Interesting.

+       buf.len = VARSIZE_ANY_EXHDR(sstate);
+       buf.maxlen = 0;
+       buf.cursor = 0;

Perhaps it would be worth hiding that in a macro defined in
stringinfo.h?
--
Michael

#6David Rowley
dgrowleyml@gmail.com
In reply to: Michael Paquier (#5)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

Thanks for taking a look at this.

On Wed, 4 Oct 2023 at 16:57, Michael Paquier <michael@paquier.xyz> wrote:

+       buf.len = VARSIZE_ANY_EXHDR(sstate);
+       buf.maxlen = 0;
+       buf.cursor = 0;

Perhaps it would be worth hiding that in a macro defined in
stringinfo.h?

The original patch had a new function in stringinfo.c which allowed a
StringInfoData to be initialised from an existing string with some
given length. Tom wasn't a fan of that because there wasn't any
protection against someone trying to use the given StringInfoData and
then calling appendStringInfo to append another string. That can't be
done in this case as we can't repalloc the VARDATA_ANY(state) pointer
due to it not pointing directly to a palloc'd chunk. Tom's complaint
seemed to be about having a reusable function which could be abused,
so I modified the patch to remove the reusable code. I think your
macro idea in stringinfo.h would put the patch in the same position as
it was initially.

It would be possible to do something like have maxlen == -1 mean that
the StringInfoData.data field isn't being managed internally in
stringinfo.c and then have all the appendStringInfo functions check
for that, but I really don't want to add overhead to everything that
uses appendStringInfo just for this.

David

#7Michael Paquier
michael@paquier.xyz
In reply to: David Rowley (#6)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Wed, Oct 04, 2023 at 07:47:11PM +1300, David Rowley wrote:

The original patch had a new function in stringinfo.c which allowed a
StringInfoData to be initialised from an existing string with some
given length. Tom wasn't a fan of that because there wasn't any
protection against someone trying to use the given StringInfoData and
then calling appendStringInfo to append another string. That can't be
done in this case as we can't repalloc the VARDATA_ANY(state) pointer
due to it not pointing directly to a palloc'd chunk. Tom's complaint
seemed to be about having a reusable function which could be abused,
so I modified the patch to remove the reusable code. I think your
macro idea in stringinfo.h would put the patch in the same position as
it was initially.

Ahem, well. Based on this argument my own argument does not hold
much. Perhaps I'd still use a macro at the top of array_userfuncs.c
and numeric.c, to avoid repeating the same pattern respectively two
and four times, documenting once on top of both macros that this is a
fake StringInfo because of the reasons documented in these code paths.
--
Michael

#8David Rowley
dgrowleyml@gmail.com
In reply to: Michael Paquier (#7)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Thu, 5 Oct 2023 at 18:23, Michael Paquier <michael@paquier.xyz> wrote:

On Wed, Oct 04, 2023 at 07:47:11PM +1300, David Rowley wrote:

The original patch had a new function in stringinfo.c which allowed a
StringInfoData to be initialised from an existing string with some
given length. Tom wasn't a fan of that because there wasn't any
protection against someone trying to use the given StringInfoData and
then calling appendStringInfo to append another string. That can't be
done in this case as we can't repalloc the VARDATA_ANY(state) pointer
due to it not pointing directly to a palloc'd chunk. Tom's complaint
seemed to be about having a reusable function which could be abused,
so I modified the patch to remove the reusable code. I think your
macro idea in stringinfo.h would put the patch in the same position as
it was initially.

Ahem, well. Based on this argument my own argument does not hold
much. Perhaps I'd still use a macro at the top of array_userfuncs.c
and numeric.c, to avoid repeating the same pattern respectively two
and four times, documenting once on top of both macros that this is a
fake StringInfo because of the reasons documented in these code paths.

I looked at the patch again and I just couldn't bring myself to change
it to that. If it were a macro going into stringinfo.h then I'd agree
with having a macro or inline function as it would allow the reader to
conceptualise what's happening after learning what the function does.
Having multiple macros defined in various C files means that much
harder as there are more macros to learn. Since we're only talking 4
lines of code, I think I'd rather reduce the number of hops the reader
must do to find out what's going on and just leave the patch as is.

I considered if it might be better to reduce the 4 lines down to 3 by
chaining the assignments like:

buf.maxlen = buf.cursor = 0;

but I think I might instead change it so that maxlen gets set to -1 to
follow what's done in LogicalParallelApplyLoop() and
LogicalRepApplyLoop(). In the absence of having a function/macro in
stringinfo.h, it might make grepping for this type of thing easier.

If anyone else has a good argument for having multiple macros for this
purpose then I could reconsider.

David

#9David Rowley
dgrowleyml@gmail.com
In reply to: David Rowley (#8)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Thu, 5 Oct 2023 at 21:24, David Rowley <dgrowleyml@gmail.com> wrote:

On Thu, 5 Oct 2023 at 18:23, Michael Paquier <michael@paquier.xyz> wrote:

Ahem, well. Based on this argument my own argument does not hold
much. Perhaps I'd still use a macro at the top of array_userfuncs.c
and numeric.c, to avoid repeating the same pattern respectively two
and four times, documenting once on top of both macros that this is a
fake StringInfo because of the reasons documented in these code paths.

I looked at the patch again and I just couldn't bring myself to change
it to that. If it were a macro going into stringinfo.h then I'd agree
with having a macro or inline function as it would allow the reader to
conceptualise what's happening after learning what the function does.

I've pushed this patch. I didn't go with the macros in the end. I
just felt it wasn't an improvement and none of the existing code which
does the same thing bothers with a macro. I got the idea you were not
particularly for the macro given that you used the word "Perhaps".

Anyway, thank you for having a look at this.

David

#10Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#9)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

On Thu, 5 Oct 2023 at 21:24, David Rowley <dgrowleyml@gmail.com> wrote:

I looked at the patch again and I just couldn't bring myself to change
it to that. If it were a macro going into stringinfo.h then I'd agree
with having a macro or inline function as it would allow the reader to
conceptualise what's happening after learning what the function does.

I've pushed this patch. I didn't go with the macros in the end. I
just felt it wasn't an improvement and none of the existing code which
does the same thing bothers with a macro. I got the idea you were not
particularly for the macro given that you used the word "Perhaps".

Sorry for not having paid more attention to this thread ... but
I'm pretty desperately unhappy with the patch as-pushed. I agree
with the criticism that this is a very repetitive coding pattern
that could have used a macro. But my real problem with this:

+   buf.data = VARDATA_ANY(sstate);
+   buf.len = VARSIZE_ANY_EXHDR(sstate);
+   buf.maxlen = 0;
+   buf.cursor = 0;

is that it totally breaks the StringInfo API without even
attempting to fix the API specs that it falsifies,
particularly this in stringinfo.h:

* maxlen is the allocated size in bytes of 'data', i.e. the maximum
* string size (including the terminating '\0' char) that we can
* currently store in 'data' without having to reallocate
* more space. We must always have maxlen > len.

I could see inventing a notion of a "read-only StringInfo"
to legitimize what you've done here, but you didn't bother
to try. I do not like this one bit. This is a fairly
fundamental API and we shouldn't be so cavalier about
breaking it.

regards, tom lane

#11David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#10)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Mon, 9 Oct 2023 at 17:37, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Sorry for not having paid more attention to this thread ... but
I'm pretty desperately unhappy with the patch as-pushed. I agree
with the criticism that this is a very repetitive coding pattern
that could have used a macro. But my real problem with this:

+   buf.data = VARDATA_ANY(sstate);
+   buf.len = VARSIZE_ANY_EXHDR(sstate);
+   buf.maxlen = 0;
+   buf.cursor = 0;

is that it totally breaks the StringInfo API without even
attempting to fix the API specs that it falsifies,
particularly this in stringinfo.h:

* maxlen is the allocated size in bytes of 'data', i.e. the maximum
* string size (including the terminating '\0' char) that we can
* currently store in 'data' without having to reallocate
* more space. We must always have maxlen > len.

I could see inventing a notion of a "read-only StringInfo"
to legitimize what you've done here, but you didn't bother
to try. I do not like this one bit. This is a fairly
fundamental API and we shouldn't be so cavalier about
breaking it.

You originally called the centralised logic a "loaded foot-gun" [1]/messages/by-id/770055.1676183953@sss.pgh.pa.us,
but now you're complaining about a lack of loaded foot-gun and want a
macro? Which part did I misunderstand? Enlighten me, please.

Here are some more thoughts on how we could improve this:

1. Adjust the definition of StringInfoData.maxlen to define that -1
means the StringInfoData's buffer is externally managed.
2. Adjust enlargeStringInfo() to add a check for maxlen = -1 and have
it palloc, say, pg_next_pow2(str->len * 2) bytes and memcpy the
existing (externally managed string) into the newly palloc'd buffer.
3. Add a new function along the lines of what I originally proposed to
allow init of a StringInfoData using an existing allocated string
which sets maxlen = -1.
4. Update all the existing places, including the ones I just committed
(plus the ones you committed in ba1e066e4) to make use of the function
added in #3.

Better ideas?

David

[1]: /messages/by-id/770055.1676183953@sss.pgh.pa.us

#12David Rowley
dgrowleyml@gmail.com
In reply to: David Rowley (#11)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Mon, 9 Oct 2023 at 21:17, David Rowley <dgrowleyml@gmail.com> wrote:

Here are some more thoughts on how we could improve this:

1. Adjust the definition of StringInfoData.maxlen to define that -1
means the StringInfoData's buffer is externally managed.
2. Adjust enlargeStringInfo() to add a check for maxlen = -1 and have
it palloc, say, pg_next_pow2(str->len * 2) bytes and memcpy the
existing (externally managed string) into the newly palloc'd buffer.
3. Add a new function along the lines of what I originally proposed to
allow init of a StringInfoData using an existing allocated string
which sets maxlen = -1.
4. Update all the existing places, including the ones I just committed
(plus the ones you committed in ba1e066e4) to make use of the function
added in #3.

I just spent the past few hours playing around with the attached WIP
patch to try to clean up the various places where we manually build
StringInfoDatas around the tree.

While working on this, I added an Assert in the new
initStringInfoFromStringWithLen function to ensure that data[len] ==
'\0' per the "There is guaranteed to be a terminating '\0' at
data[len]" comment in stringinfo.h. It looks like we have some
existing breakers of this rule.

If you apply the attached patch to 608fd198de~1 and ignore the
rejected hunks from the deserial functions, you'll see an Assert
failure during 023_twophase_stream.pl

023_twophase_stream_subscriber.log indicates:
TRAP: failed Assert("data[len] == '\0'"), File:
"../../../../src/include/lib/stringinfo.h", Line: 97, PID: 1073141
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (ExceptionalCondition+0x70)[0x56160451e9d0]
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (ParallelApplyWorkerMain+0x53c)[0x5616043618cc]
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (StartBackgroundWorker+0x20b)[0x56160434452b]

So it seems like we have some existing issues with
LogicalParallelApplyLoop(). The code there does not properly NUL
terminate the StringInfoData.data field. There are some examples in
exec_bind_message() of how that could be fixed. I've CC'd Amit to let
him know about this.

I'll also need to revert 608fd198 as this also highlights that setting
the StringInfoData.data to point to a bytea Datum can't be done either
as those aren't NUL terminated strings.

If people think it's worthwhile having something like the attached to
try to eliminate our need to manually build StringInfoDatas then I can
spend more time on it once LogicalParallelApplyLoop() is fixed.

David

Attachments:

initstringinfowithlen.patchtext/plain; charset=US-ASCII; name=initstringinfowithlen.patchDownload
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 82f48a488e..fdfbd45e2c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -774,10 +774,7 @@ LogicalParallelApplyLoop(shm_mq_handle *mqh)
 			if (len == 0)
 				elog(ERROR, "invalid message length");
 
-			s.cursor = 0;
-			s.maxlen = -1;
-			s.data = (char *) data;
-			s.len = len;
+			initStringInfoFromStringWithLen(&s, data, len);
 
 			/*
 			 * The first byte of messages sent from leader apply worker to
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index d52c8963eb..0d65e2836b 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -879,6 +879,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	/* Read the data */
 	for (i = 0; i < natts; i++)
 	{
+		char	   *buff;
 		char		kind;
 		int			len;
 		StringInfo	value = &tuple->colvalues[i];
@@ -899,19 +900,17 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 				len = pq_getmsgint(in, 4);	/* read length */
 
 				/* and data */
-				value->data = palloc(len + 1);
-				pq_copymsgbytes(in, value->data, len);
+				buff = palloc(len + 1);
+				pq_copymsgbytes(in, buff, len);
 
 				/*
 				 * Not strictly necessary for LOGICALREP_COLUMN_BINARY, but
 				 * per StringInfo practice.
 				 */
-				value->data[len] = '\0';
+				buff[len] = '\0';
 
-				/* make StringInfo fully valid */
-				value->len = len;
-				value->cursor = 0;
-				value->maxlen = len;
+				/* make StringInfo */
+				initStringInfoFromStringWithLen(value, buff, len);
 				break;
 			default:
 				elog(ERROR, "unrecognized data representation type '%c'", kind);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 597947410f..b4bf3111cf 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3582,10 +3582,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
 
-					s.data = buf;
-					s.len = len;
-					s.cursor = 0;
-					s.maxlen = -1;
+					initStringInfoFromStringWithLen(&s, buf, len);
 
 					c = pq_getmsgbyte(&s);
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 21b9763183..17407d9edb 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1816,23 +1816,18 @@ exec_bind_message(StringInfo input_message)
 
 			if (!isNull)
 			{
-				const char *pvalue = pq_getmsgbytes(input_message, plength);
+				char *pvalue = unconstify(char *, pq_getmsgbytes(input_message, plength));
 
 				/*
-				 * Rather than copying data around, we just set up a phony
-				 * StringInfo pointing to the correct portion of the message
-				 * buffer.  We assume we can scribble on the message buffer so
-				 * as to maintain the convention that StringInfos have a
-				 * trailing null.  This is grotty but is a big win when
-				 * dealing with very large parameter strings.
+				 * Rather than copying data around, we just initialize a StringInfo
+				 * pointing to the correct portion of the message buffer.  We assume we
+				 * can scribble on the message buffer so as to maintain the convention
+				 * that StringInfos have a trailing null.  This is grotty but is a big win
+				 * when dealing with very large parameter strings.
 				 */
-				pbuf.data = unconstify(char *, pvalue);
-				pbuf.maxlen = plength + 1;
-				pbuf.len = plength;
-				pbuf.cursor = 0;
-
-				csave = pbuf.data[plength];
-				pbuf.data[plength] = '\0';
+				csave = pvalue[plength];
+				pvalue[plength] = '\0';
+				initStringInfoFromStringWithLen(&pbuf, pvalue, plength);
 			}
 			else
 			{
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 7f87df45df..7731a6a76f 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -722,14 +722,9 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 
 	sstate = PG_GETARG_BYTEA_PP(0);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -1133,14 +1128,9 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 
 	sstate = PG_GETARG_BYTEA_PP(0);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index f4b885005f..6e7826631f 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5189,14 +5189,9 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 
 	init_var(&tmp_var);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5305,14 +5300,9 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 
 	init_var(&tmp_var);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5676,14 +5666,9 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 
 	init_var(&tmp_var);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5867,14 +5852,9 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 
 	init_var(&tmp_var);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index ad176651d8..fafd32c116 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -623,21 +623,19 @@ record_recv(PG_FUNCTION_ARGS)
 		}
 		else
 		{
+			char	   *strbuff;
+
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
+			 * Initalize a new StringInfo using the correct portion of the input
+			 * buffer.  We assume we can scribble on the input buffer so as to maintain
 			 * the convention that StringInfos have a trailing null.
 			 */
-			item_buf.data = &buf->data[buf->cursor];
-			item_buf.maxlen = itemlen + 1;
-			item_buf.len = itemlen;
-			item_buf.cursor = 0;
-
+			strbuff = &buf->data[buf->cursor];
 			buf->cursor += itemlen;
+			buf->data[buf->cursor] = '\0';
+			initStringInfoFromStringWithLen(&item_buf, strbuff, itemlen);
 
 			csave = buf->data[buf->cursor];
-			buf->data[buf->cursor] = '\0';
 
 			bufptr = &item_buf;
 			nulls[i] = false;
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 1aff04fa77..ade96bbdc8 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -5288,14 +5288,9 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 
 	sstate = PG_GETARG_BYTEA_PP(0);
 
-	/*
-	 * Fake up a StringInfo pointing to the bytea's value so we can "receive"
-	 * the serialized aggregate state value.
-	 */
-	buf.data = VARDATA_ANY(sstate);
-	buf.len = VARSIZE_ANY_EXHDR(sstate);
-	buf.maxlen = 0;
-	buf.cursor = 0;
+	initStringInfoFromStringWithLen(&buf,
+									VARDATA_ANY(sstate),
+									VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeStringAggState(fcinfo);
 
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..b87073c924 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -30,6 +30,7 @@
 #endif
 
 #include "lib/stringinfo.h"
+#include "port/pg_bitutils.h"
 
 
 /*
@@ -320,6 +321,24 @@ enlargeStringInfo(StringInfo str, int needed)
 	if (needed <= str->maxlen)
 		return;					/* got enough space already */
 
+
+	/*
+	 * maxlen may be -1 if the string is externally managed.  Check for that and
+	 * palloc a new buffer instead of reallocating the existing buffer
+	 */
+	if (unlikely(str->maxlen == -1))
+	{
+		char *newdata;
+
+		/* make the string no longer read-only */
+		newlen = pg_nextpower2_32(str->len * 2);
+		newdata = (char *) palloc(newlen);
+		memcpy(newdata, str->data, str->len + 1);
+		str->data = newdata;
+		str->maxlen = newlen;
+		return;
+	}
+
 	/*
 	 * We don't want to allocate just a little more space with each append;
 	 * for efficiency, double the buffer size each time it overflows.
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..b9161d6680 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -27,7 +27,10 @@
  *		maxlen	is the allocated size in bytes of 'data', i.e. the maximum
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
- *				more space.  We must always have maxlen > len.
+ *				more space.  We must always have maxlen > len except in the
+ *				case when maxlen is set to -1 in which case 'data' is classed
+				"read-only".  Before appending to a read-only StringInfoData we
+				must always copy the 'data' out into a new allocation.
  *		cursor	is initialized to zero by makeStringInfo or initStringInfo,
  *				but is not otherwise touched by the stringinfo.c routines.
  *				Some routines use it to scan through a StringInfo.
@@ -79,6 +82,26 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initStringInfoFromStringWithLen
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  The caller is responsible for ensuring the given string
+ * remains valid as long as the StringInfo is.  The given string must be
+ * NUL terminated at 'len' bytes.  Calls to this are used in performance
+ * critical locations where allocating a new buffer and copying would be too
+ * costly.
+ */
+static inline void
+initStringInfoFromStringWithLen(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->maxlen = -1;
+	str->len = len;
+	str->cursor = 0;
+}
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
#13Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#12)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

On Mon, 9 Oct 2023 at 21:17, David Rowley <dgrowleyml@gmail.com> wrote:

Here are some more thoughts on how we could improve this:

1. Adjust the definition of StringInfoData.maxlen to define that -1
means the StringInfoData's buffer is externally managed.
2. Adjust enlargeStringInfo() to add a check for maxlen = -1 and have
it palloc, say, pg_next_pow2(str->len * 2) bytes and memcpy the
existing (externally managed string) into the newly palloc'd buffer.
3. Add a new function along the lines of what I originally proposed to
allow init of a StringInfoData using an existing allocated string
which sets maxlen = -1.
4. Update all the existing places, including the ones I just committed
(plus the ones you committed in ba1e066e4) to make use of the function
added in #3.

Hm. I'd be inclined to use maxlen == 0 as the indicator of a read-only
buffer, just because that would not create a problem if we ever want
to change it to an unsigned type. Other than that, I agree with the
idea of using a special maxlen value to indicate that the buffer is
read-only and not owned by the StringInfo. We need to nail down the
exact semantics though.

While working on this, I added an Assert in the new
initStringInfoFromStringWithLen function to ensure that data[len] ==
'\0' per the "There is guaranteed to be a terminating '\0' at
data[len]" comment in stringinfo.h. It looks like we have some
existing breakers of this rule.

Ugh. The point that 608fd198d also broke the terminating-nul
convention was something that occurred to me after sending
my previous message. That's something we can't readily accommodate
within the concept of a read-only buffer, but I think we can't
give it up without risking a lot of obscure bugs.

I'll also need to revert 608fd198 as this also highlights that setting
the StringInfoData.data to point to a bytea Datum can't be done either
as those aren't NUL terminated strings.

Yeah. I would revert that as a separate commit and then think about
how we want to proceed, but I generally agree that there could be
value in the idea of a setup function that accepts a caller-supplied
buffer.

regards, tom lane

#14David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#13)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Tue, 10 Oct 2023 at 06:38, Tom Lane <tgl@sss.pgh.pa.us> wrote:

Hm. I'd be inclined to use maxlen == 0 as the indicator of a read-only
buffer, just because that would not create a problem if we ever want
to change it to an unsigned type. Other than that, I agree with the
idea of using a special maxlen value to indicate that the buffer is
read-only and not owned by the StringInfo. We need to nail down the
exact semantics though.

I've attached a slightly more worked on patch that makes maxlen == 0
mean read-only. Unsure if a macro is worthwhile there or not.

The patch still fails during 023_twophase_stream.pl for the reasons
mentioned upthread. Getting rid of the Assert in
initStringInfoFromStringWithLen() allows it to pass.

One thought I had about this is that the memory context behaviour
might catch someone out at some point. Right now if you do
initStringInfo() the memory context of the "data" field will be
CurrentMemoryContext, but if someone does
initStringInfoFromStringWithLen() and then changes to some other
memory context before doing an appendStringInfo on that string, then
we'll allocate "data" in whatever that memory context is. Maybe that's
ok if we document it. Fixing it would mean adding a MemoryContext
field to StringInfoData which would be set to CurrentMemoryContext
during initStringInfo() and initStringInfoFromStringWithLen().

I'm not fully happy with the extra code added in enlargeStringInfo().
It's a little repetitive. Fixing it up would mean having to have a
boolean variable to mark if the string was readonly so at the end we'd
know to repalloc or palloc/memcpy. For now, I just marked that code
as unlikely() since there's no place in the code base that uses it.

David

Attachments:

initStringInfoFromStringWithLen_v2.patchtext/plain; charset=US-ASCII; name=initStringInfoFromStringWithLen_v2.patchDownload
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 82f48a488e..fdfbd45e2c 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -774,10 +774,7 @@ LogicalParallelApplyLoop(shm_mq_handle *mqh)
 			if (len == 0)
 				elog(ERROR, "invalid message length");
 
-			s.cursor = 0;
-			s.maxlen = -1;
-			s.data = (char *) data;
-			s.len = len;
+			initStringInfoFromStringWithLen(&s, data, len);
 
 			/*
 			 * The first byte of messages sent from leader apply worker to
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index d52c8963eb..e51a2b7ce1 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -879,6 +879,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	/* Read the data */
 	for (i = 0; i < natts; i++)
 	{
+		char	   *buff;
 		char		kind;
 		int			len;
 		StringInfo	value = &tuple->colvalues[i];
@@ -899,19 +900,16 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 				len = pq_getmsgint(in, 4);	/* read length */
 
 				/* and data */
-				value->data = palloc(len + 1);
-				pq_copymsgbytes(in, value->data, len);
+				buff = palloc(len + 1);
+				pq_copymsgbytes(in, buff, len);
 
 				/*
 				 * Not strictly necessary for LOGICALREP_COLUMN_BINARY, but
 				 * per StringInfo practice.
 				 */
-				value->data[len] = '\0';
+				buff[len] = '\0';
 
-				/* make StringInfo fully valid */
-				value->len = len;
-				value->cursor = 0;
-				value->maxlen = len;
+				initStringInfoFromStringWithLen(value, buff, len);
 				break;
 			default:
 				elog(ERROR, "unrecognized data representation type '%c'", kind);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 597947410f..b4bf3111cf 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3582,10 +3582,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
 
-					s.data = buf;
-					s.len = len;
-					s.cursor = 0;
-					s.maxlen = -1;
+					initStringInfoFromStringWithLen(&s, buf, len);
 
 					c = pq_getmsgbyte(&s);
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 21b9763183..d48029038b 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1816,23 +1816,19 @@ exec_bind_message(StringInfo input_message)
 
 			if (!isNull)
 			{
-				const char *pvalue = pq_getmsgbytes(input_message, plength);
+				char *pvalue;
 
 				/*
-				 * Rather than copying data around, we just set up a phony
-				 * StringInfo pointing to the correct portion of the message
-				 * buffer.  We assume we can scribble on the message buffer so
-				 * as to maintain the convention that StringInfos have a
-				 * trailing null.  This is grotty but is a big win when
-				 * dealing with very large parameter strings.
+				 * Rather than copying data around, we just initialize a StringInfo
+				 * pointing to the correct portion of the message buffer.  We assume we
+				 * can scribble on the message buffer so as to maintain the convention
+				 * that StringInfos have a trailing null.  This is grotty but is a big win
+				 * when dealing with very large parameter strings.
 				 */
-				pbuf.data = unconstify(char *, pvalue);
-				pbuf.maxlen = plength + 1;
-				pbuf.len = plength;
-				pbuf.cursor = 0;
-
-				csave = pbuf.data[plength];
-				pbuf.data[plength] = '\0';
+				pvalue = unconstify(char *, pq_getmsgbytes(input_message, plength));
+				csave = pvalue[plength];
+				pvalue[plength] = '\0';
+				initStringInfoFromStringWithLen(&pbuf, pvalue, plength);
 			}
 			else
 			{
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index ad176651d8..e76c723f49 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -623,21 +623,18 @@ record_recv(PG_FUNCTION_ARGS)
 		}
 		else
 		{
+			char	   *strbuff;
+
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
+			 * Initalize a new StringInfo using the correct portion of the input
+			 * buffer.  We assume we can scribble on the input buffer so as to maintain
 			 * the convention that StringInfos have a trailing null.
 			 */
-			item_buf.data = &buf->data[buf->cursor];
-			item_buf.maxlen = itemlen + 1;
-			item_buf.len = itemlen;
-			item_buf.cursor = 0;
-
+			strbuff = &buf->data[buf->cursor];
 			buf->cursor += itemlen;
-
 			csave = buf->data[buf->cursor];
 			buf->data[buf->cursor] = '\0';
+			initStringInfoFromStringWithLen(&item_buf, strbuff, itemlen);
 
 			bufptr = &item_buf;
 			nulls[i] = false;
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..2cf57a804f 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -30,6 +30,7 @@
 #endif
 
 #include "lib/stringinfo.h"
+#include "port/pg_bitutils.h"
 
 
 /*
@@ -320,24 +321,50 @@ enlargeStringInfo(StringInfo str, int needed)
 	if (needed <= str->maxlen)
 		return;					/* got enough space already */
 
-	/*
-	 * We don't want to allocate just a little more space with each append;
-	 * for efficiency, double the buffer size each time it overflows.
-	 * Actually, we might need to more than double it if 'needed' is big...
-	 */
-	newlen = 2 * str->maxlen;
-	while (needed > newlen)
-		newlen = 2 * newlen;
-
-	/*
-	 * Clamp to MaxAllocSize in case we went past it.  Note we are assuming
-	 * here that MaxAllocSize <= INT_MAX/2, else the above loop could
-	 * overflow.  We will still have newlen >= needed.
-	 */
-	if (newlen > (int) MaxAllocSize)
-		newlen = (int) MaxAllocSize;
-
-	str->data = (char *) repalloc(str->data, newlen);
-
-	str->maxlen = newlen;
+	if (likely(str->maxlen != 0))
+	{
+		/*
+		 * We don't want to allocate just a little more space with each append;
+		 * for efficiency, double the buffer size each time it overflows.
+		 * Actually, we might need to more than double it if 'needed' is big...
+		 */
+		newlen = 2 * str->maxlen;
+		while (needed > newlen)
+			newlen = 2 * newlen;
+
+		/*
+		 * Clamp to MaxAllocSize in case we went past it.  Note we are assuming
+		 * here that MaxAllocSize <= INT_MAX/2, else the above loop could
+		 * overflow.  We will still have newlen >= needed.
+		 */
+		if (newlen > (int) MaxAllocSize)
+			newlen = (int) MaxAllocSize;
+
+		str->data = (char *) repalloc(str->data, newlen);
+
+		str->maxlen = newlen;
+	}
+	else
+	{
+		char *newdata;
+
+		/*
+		 * The StringInfo may be read-only if initialized with
+		 * initStringInfoFromStringWithLen().  This means we need to copy the
+		 * read-only string out into a newly palloc'd buffer.
+		 */
+		newlen = pg_nextpower2_32(str->len) * 2;
+		while (needed > newlen)
+			newlen = 2 * newlen;
+
+		if (newlen > (int) MaxAllocSize)
+			newlen = (int) MaxAllocSize;
+
+		newdata = (char *) palloc(newlen);
+		memcpy(newdata, str->data, str->len + 1);
+
+		str->data = newdata;
+		str->maxlen = newlen;
+		return;
+	}
 }
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..f3739790a7 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -27,7 +27,10 @@
  *		maxlen	is the allocated size in bytes of 'data', i.e. the maximum
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
- *				more space.  We must always have maxlen > len.
+ *				more space.  We must always have maxlen > len except in the
+ *				case when maxlen is set to 0, in which case 'data' is classed
+ *				"read-only".  Before appending to a read-only StringInfoData we
+ *				must always copy the 'data' out into a new allocation.
  *		cursor	is initialized to zero by makeStringInfo or initStringInfo,
  *				but is not otherwise touched by the stringinfo.c routines.
  *				Some routines use it to scan through a StringInfo.
@@ -79,6 +82,26 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initStringInfoFromStringWithLen
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  The caller is responsible for ensuring the given string
+ * remains valid as long as the StringInfo does.  The given string must be
+ * NUL terminated at 'len' bytes.  Calls to this are used in performance
+ * critical locations where allocating a new buffer and copying would be too
+ * costly.
+ */
+static inline void
+initStringInfoFromStringWithLen(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->maxlen = 0;
+	str->len = len;
+	str->cursor = 0;
+}
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
#15vignesh C
vignesh21@gmail.com
In reply to: David Rowley (#12)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Mon, 9 Oct 2023 at 16:20, David Rowley <dgrowleyml@gmail.com> wrote:

On Mon, 9 Oct 2023 at 21:17, David Rowley <dgrowleyml@gmail.com> wrote:

Here are some more thoughts on how we could improve this:

1. Adjust the definition of StringInfoData.maxlen to define that -1
means the StringInfoData's buffer is externally managed.
2. Adjust enlargeStringInfo() to add a check for maxlen = -1 and have
it palloc, say, pg_next_pow2(str->len * 2) bytes and memcpy the
existing (externally managed string) into the newly palloc'd buffer.
3. Add a new function along the lines of what I originally proposed to
allow init of a StringInfoData using an existing allocated string
which sets maxlen = -1.
4. Update all the existing places, including the ones I just committed
(plus the ones you committed in ba1e066e4) to make use of the function
added in #3.

I just spent the past few hours playing around with the attached WIP
patch to try to clean up the various places where we manually build
StringInfoDatas around the tree.

While working on this, I added an Assert in the new
initStringInfoFromStringWithLen function to ensure that data[len] ==
'\0' per the "There is guaranteed to be a terminating '\0' at
data[len]" comment in stringinfo.h. It looks like we have some
existing breakers of this rule.

If you apply the attached patch to 608fd198de~1 and ignore the
rejected hunks from the deserial functions, you'll see an Assert
failure during 023_twophase_stream.pl

023_twophase_stream_subscriber.log indicates:
TRAP: failed Assert("data[len] == '\0'"), File:
"../../../../src/include/lib/stringinfo.h", Line: 97, PID: 1073141
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (ExceptionalCondition+0x70)[0x56160451e9d0]
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (ParallelApplyWorkerMain+0x53c)[0x5616043618cc]
postgres: subscriber: logical replication parallel apply worker for
subscription 16396 (StartBackgroundWorker+0x20b)[0x56160434452b]

So it seems like we have some existing issues with
LogicalParallelApplyLoop(). The code there does not properly NUL
terminate the StringInfoData.data field. There are some examples in
exec_bind_message() of how that could be fixed. I've CC'd Amit to let
him know about this.

Thanks for reporting this issue, I was able to reproduce this issue
with the steps provided. I will analyze further and start a new thread
to provide the details of the same.

Regards,
Vignesh

#16Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#14)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

I've attached a slightly more worked on patch that makes maxlen == 0
mean read-only. Unsure if a macro is worthwhile there or not.

A few thoughts:

* initStringInfoFromStringWithLen() is kind of a mouthful.
How about "initStringInfoWithBuf", or something like that?

* logicalrep_read_tuple is doing something different from these
other callers: it's creating a *fully valid* StringInfo that
could be enlarged via repalloc. (Whether anything downstream
depends on that, I dunno.) Is it worth having two new init
functions, one that has that spec and initializes maxlen
appropriately, and the other that sets maxlen to 0?

* I think that this bit in the new enlargeStringInfo code path
is wrong:

+		newlen = pg_nextpower2_32(str->len) * 2;
+		while (needed > newlen)
+			newlen = 2 * newlen;

In the admittedly-unlikely case that str->len is more than half a GB
to start with, pg_nextpower2_32() will round up to 1GB and then the *2
overflows. I think you should make this just

+		newlen = pg_nextpower2_32(str->len);
+		while (needed > newlen)
+			newlen = 2 * newlen;

It's fairly likely that this path will never be taken at all,
so trying to shave a cycle or two seems unnecessary.

One thought I had about this is that the memory context behaviour
might catch someone out at some point. Right now if you do
initStringInfo() the memory context of the "data" field will be
CurrentMemoryContext, but if someone does
initStringInfoFromStringWithLen() and then changes to some other
memory context before doing an appendStringInfo on that string, then
we'll allocate "data" in whatever that memory context is. Maybe that's
ok if we document it. Fixing it would mean adding a MemoryContext
field to StringInfoData which would be set to CurrentMemoryContext
during initStringInfo() and initStringInfoFromStringWithLen().

I think documenting it is sufficient. I don't really foresee use-cases
where the string would get enlarged, anyway.

On the whole, I wonder about the value of allowing such a StringInfo to be
enlarged at all. If we are defining the case as being a "read only"
buffer, under what circumstances would it be useful to enlarge it?
I'm tempted to suggest that we should just Assert(maxlen > 0) in
enlargeStringInfo, and anywhere else in stringinfo.c that modifies
the buffer. That also removes the concern about which context the
enlargement would happen in.

I'm not really happy with what you did documentation-wise in
stringinfo.h. I suggest more like

 * StringInfoData holds information about an extensible string.
 *      data    is the current buffer for the string (allocated with palloc).
 *      len     is the current string length.  There is guaranteed to be
 *              a terminating '\0' at data[len], although this is not very
 *              useful when the string holds binary data rather than text.
 *      maxlen  is the allocated size in bytes of 'data', i.e. the maximum
 *              string size (including the terminating '\0' char) that we can
 *              currently store in 'data' without having to reallocate
-*              more space.  We must always have maxlen > len, except
+*              in the read-only case described below.
 *      cursor  is initialized to zero by makeStringInfo or initStringInfo,
 *              but is not otherwise touched by the stringinfo.c routines.
 *              Some routines use it to scan through a StringInfo.
+*
+* As a special case, a StringInfoData can be initialized with a read-only
+* string buffer.  In this case "data" does not necessarily point at a
+* palloc'd chunk, and management of the buffer storage is the caller's
+* responsibility.  maxlen is set to zero to indicate that this is the case.

Also, the following comment block asserting that there are "two ways"
to initialize a StringInfo needs work, and I guess so does the above-
cited comment about the cursor field.

regards, tom lane

#17David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#16)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Wed, 11 Oct 2023 at 08:52, Tom Lane <tgl@sss.pgh.pa.us> wrote:

David Rowley <dgrowleyml@gmail.com> writes:

I've attached a slightly more worked on patch that makes maxlen == 0
mean read-only. Unsure if a macro is worthwhile there or not.

A few thoughts:

Thank you for the review.

I spent more time on this and did end up with 2 new init functions as
you mentioned. One for strictly read-only (initReadOnlyStringInfo),
which cannot be appended to, and as you mentioned, another
(initStringInfoFromString) which can accept a palloc'd buffer which
becomes managed by the stringinfo code. I know these names aren't
exactly as you mentioned. I'm open to adjusting still.

This means I got rid of the read-only conversion code in
enlargeStringInfo(). I didn't do anything to try to handle buffer
enlargement more efficiently in enlargeStringInfo() for the case where
initStringInfoFromString sets maxlen to some non-power-of-2. The
doubling code seems like it'll work ok without power-of-2 values,
it'll just end up calling repalloc() with non-power-of-2 values.

I did also wonder if resetStringInfo() would have any business
touching the existing buffer in a read-only StringInfo and came to the
conclusion that it wouldn't be very read-only if we allowed
resetStringInfo() to do its thing on it. I added an Assert to fail if
resetStringInfo() receives a read-only StringInfo.

Also, since it's still being discussed, I left out the adjustment to
LogicalParallelApplyLoop(). That also allows the tests to pass
without the failing Assert that was checking for the NUL terminator.

David

Attachments:

initstringinfo_changes_v3.patchtext/plain; charset=US-ASCII; name=initstringinfo_changes_v3.patchDownload
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index d52c8963eb..ce9d5b4059 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -879,6 +879,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	/* Read the data */
 	for (i = 0; i < natts; i++)
 	{
+		char	   *buff;
 		char		kind;
 		int			len;
 		StringInfo	value = &tuple->colvalues[i];
@@ -899,19 +900,16 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 				len = pq_getmsgint(in, 4);	/* read length */
 
 				/* and data */
-				value->data = palloc(len + 1);
-				pq_copymsgbytes(in, value->data, len);
+				buff = palloc(len + 1);
+				pq_copymsgbytes(in, buff, len);
 
 				/*
 				 * Not strictly necessary for LOGICALREP_COLUMN_BINARY, but
 				 * per StringInfo practice.
 				 */
-				value->data[len] = '\0';
+				buff[len] = '\0';
 
-				/* make StringInfo fully valid */
-				value->len = len;
-				value->cursor = 0;
-				value->maxlen = len;
+				initStringInfoFromString(value, buff, len);
 				break;
 			default:
 				elog(ERROR, "unrecognized data representation type '%c'", kind);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 597947410f..b574188d70 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3582,10 +3582,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
 
-					s.data = buf;
-					s.len = len;
-					s.cursor = 0;
-					s.maxlen = -1;
+					initReadOnlyStringInfo(&s, buf, len);
 
 					c = pq_getmsgbyte(&s);
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index f3c9f1f9ba..94b963d6e6 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1816,23 +1816,19 @@ exec_bind_message(StringInfo input_message)
 
 			if (!isNull)
 			{
-				const char *pvalue = pq_getmsgbytes(input_message, plength);
+				char *pvalue;
 
 				/*
-				 * Rather than copying data around, we just set up a phony
-				 * StringInfo pointing to the correct portion of the message
-				 * buffer.  We assume we can scribble on the message buffer so
-				 * as to maintain the convention that StringInfos have a
-				 * trailing null.  This is grotty but is a big win when
-				 * dealing with very large parameter strings.
+				 * Rather than copying data around, we just initialize a StringInfo
+				 * pointing to the correct portion of the message buffer.  We assume we
+				 * can scribble on the message buffer so as to maintain the convention
+				 * that StringInfos have a trailing null.  This is grotty but is a big win
+				 * when dealing with very large parameter strings.
 				 */
-				pbuf.data = unconstify(char *, pvalue);
-				pbuf.maxlen = plength + 1;
-				pbuf.len = plength;
-				pbuf.cursor = 0;
-
-				csave = pbuf.data[plength];
-				pbuf.data[plength] = '\0';
+				pvalue = unconstify(char *, pq_getmsgbytes(input_message, plength));
+				csave = pvalue[plength];
+				pvalue[plength] = '\0';
+				initReadOnlyStringInfo(&pbuf, pvalue, plength);
 			}
 			else
 			{
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index ad176651d8..c7ee263439 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -623,21 +623,18 @@ record_recv(PG_FUNCTION_ARGS)
 		}
 		else
 		{
+			char	   *strbuff;
+
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
+			 * Initalize a new StringInfo using the correct portion of the input
+			 * buffer.  We assume we can scribble on the input buffer so as to maintain
 			 * the convention that StringInfos have a trailing null.
 			 */
-			item_buf.data = &buf->data[buf->cursor];
-			item_buf.maxlen = itemlen + 1;
-			item_buf.len = itemlen;
-			item_buf.cursor = 0;
-
+			strbuff = &buf->data[buf->cursor];
 			buf->cursor += itemlen;
-
 			csave = buf->data[buf->cursor];
 			buf->data[buf->cursor] = '\0';
+			initReadOnlyStringInfo(&item_buf, strbuff, itemlen);
 
 			bufptr = &item_buf;
 			nulls[i] = false;
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..6897c78d9f 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -30,6 +30,7 @@
 #endif
 
 #include "lib/stringinfo.h"
+#include "port/pg_bitutils.h"
 
 
 /*
@@ -74,6 +75,9 @@ initStringInfo(StringInfo str)
 void
 resetStringInfo(StringInfo str)
 {
+	/* Don't allow resets of read-only StringInfos */
+	Assert(str->maxlen != 0);
+
 	str->data[0] = '\0';
 	str->len = 0;
 	str->cursor = 0;
@@ -284,6 +288,9 @@ enlargeStringInfo(StringInfo str, int needed)
 {
 	int			newlen;
 
+	/* Validate this is not a read-only StringInfo */
+	Assert(str->maxlen != 0);
+
 	/*
 	 * Guard against out-of-range "needed" values.  Without this, we can get
 	 * an overflow or infinite loop in the following.
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..3bd605d528 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -27,10 +27,18 @@
  *		maxlen	is the allocated size in bytes of 'data', i.e. the maximum
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
- *				more space.  We must always have maxlen > len.
- *		cursor	is initialized to zero by makeStringInfo or initStringInfo,
- *				but is not otherwise touched by the stringinfo.c routines.
- *				Some routines use it to scan through a StringInfo.
+ *				more space.  We must always have maxlen > len, except
+ *				in the read-only case described below.
+ *		cursor	is initialized to zero by makeStringInfo, initStringInfo,
+ *				initReadOnlyStringInfo and initStringInfoFromString but is not
+ *				otherwise touched by the stringinfo.c routines.  Some routines
+ *				use it to scan through a StringInfo.
+ *
+ * As a special case, a StringInfoData can be initialized with a read-only
+ * string buffer.  In this case "data" does not necessarily point at a
+ * palloc'd chunk, and management of the buffer storage is the caller's
+ * responsibility.  maxlen is set to zero to indicate that this is the case.
+ * Read-only StringInfoDatas cannot be appended to.
  *-------------------------
  */
 typedef struct StringInfoData
@@ -45,7 +53,7 @@ typedef StringInfoData *StringInfo;
 
 
 /*------------------------
- * There are two ways to create a StringInfo object initially:
+ * There are four ways to create a StringInfo object initially:
  *
  * StringInfo stringptr = makeStringInfo();
  *		Both the StringInfoData and the data buffer are palloc'd.
@@ -56,8 +64,30 @@ typedef StringInfoData *StringInfo;
  *		This is the easiest approach for a StringInfo object that will
  *		only live as long as the current routine.
  *
+ * StringInfoData string;
+ * initReadOnlyStringInfo(&string, existingbuf, len);
+ *		The StringInfoData's data field is set to point directly to the
+ *		existing buffer and the StringInfoData's len is set to the given len.
+ *		The given buffer can point to memory that's not managed by palloc or
+ *		is pointing part way through a palloc'd chunk.  The maxlen field is
+ *		set to 0.  A read-only StringInfo cannot be appended to using any of
+ *		the appendStringInfo functions or reset with resetStringInfo().  The
+ *		given buffer must be NUL-terminated.
+ *
+ * StringInfoData string;
+ * initStringInfoFromString(&string, palloced_buf, len);
+ *		The StringInfoData's data field is set to point directly to the given
+ *		buffer and the StringInfoData's len is set to the given len.  This
+ *		method of initialization is useful when the buffer already exists.
+ *		StringInfos initialized this way can be appended to using the
+ *		appendStringInfo functions and reset with resetStringInfo().  The
+ *		given buffer must be NUL-terminated.
+ *
  * To destroy a StringInfo, pfree() the data buffer, and then pfree() the
  * StringInfoData if it was palloc'd.  There's no special support for this.
+ * However, if the StringInfo was initialized using initReadOnlyStringInfo()
+ * then the caller will need to consider if it is safe to pfree the data
+ * buffer.
  *
  * NOTE: some routines build up a string using StringInfo, and then
  * release the StringInfoData but return the data string itself to their
@@ -79,6 +109,48 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initReadOnlyStringInfo
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  The caller is responsible for ensuring the given string
+ * remains valid as long as the StringInfoData does.  The given string must be
+ * NUL terminated at 'len' bytes.  Calls to this are used in performance
+ * critical locations where allocating a new buffer and copying would be too
+ * costly.  Read-only StringInfoData's may not be appended to using any of the
+ * appendStringInfo functions or reset with resetStringInfo().
+ *
+ * 'data' does not need to point directly to a palloc'd chunk of memory.
+ */
+static inline void
+initReadOnlyStringInfo(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->maxlen = 0;	/* read-only */
+	str->len = len;
+	str->cursor = 0;
+}
+
+/*------------------------
+ * initStringInfoFromString
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  'data' must be a valid palloc'd chunk of memory that can have
+ * repalloc() called should more space be required during a call to any of the
+ * appendStringInfo functions.
+ *
+ * The given string must be NUL terminated at 'len' bytes.
+ */
+static inline void
+initStringInfoFromString(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->maxlen = str->len = len;
+	str->cursor = 0;
+}
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
#18Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#17)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

I spent more time on this and did end up with 2 new init functions as
you mentioned. One for strictly read-only (initReadOnlyStringInfo),
which cannot be appended to, and as you mentioned, another
(initStringInfoFromString) which can accept a palloc'd buffer which
becomes managed by the stringinfo code. I know these names aren't
exactly as you mentioned. I'm open to adjusting still.

This v3 looks pretty decent, although I noted one significant error
and a few minor issues:

* in initStringInfoFromString, str->maxlen must be set to len+1 not len

* comment in exec_bind_message doesn't look like pgindent will like it

* same in record_recv, plus it has a misspelling "Initalize"

* in stringinfo.c, inclusion of pg_bitutils.h seems no longer needed

I guess the next question is whether we want to stop here or
try to relax the requirement about NUL-termination. I'd be inclined
to call that a separate issue deserving a separate commit, so maybe
we should go ahead and commit this much anyway.

regards, tom lane

#19David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#18)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Mon, 16 Oct 2023 at 05:56, Tom Lane <tgl@sss.pgh.pa.us> wrote:

* in initStringInfoFromString, str->maxlen must be set to len+1 not len

* comment in exec_bind_message doesn't look like pgindent will like it

* same in record_recv, plus it has a misspelling "Initalize"

* in stringinfo.c, inclusion of pg_bitutils.h seems no longer needed

Thank you for looking again. I've addressed all of these in the attached.

I guess the next question is whether we want to stop here or
try to relax the requirement about NUL-termination. I'd be inclined
to call that a separate issue deserving a separate commit, so maybe
we should go ahead and commit this much anyway.

I am keen to see this relaxed. I agree that a separate effort is best.

David

Attachments:

initstringinfo_changes_v4.patchtext/plain; charset=US-ASCII; name=initstringinfo_changes_v4.patchDownload
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index d52c8963eb..ce9d5b4059 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -879,6 +879,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	/* Read the data */
 	for (i = 0; i < natts; i++)
 	{
+		char	   *buff;
 		char		kind;
 		int			len;
 		StringInfo	value = &tuple->colvalues[i];
@@ -899,19 +900,16 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 				len = pq_getmsgint(in, 4);	/* read length */
 
 				/* and data */
-				value->data = palloc(len + 1);
-				pq_copymsgbytes(in, value->data, len);
+				buff = palloc(len + 1);
+				pq_copymsgbytes(in, buff, len);
 
 				/*
 				 * Not strictly necessary for LOGICALREP_COLUMN_BINARY, but
 				 * per StringInfo practice.
 				 */
-				value->data[len] = '\0';
+				buff[len] = '\0';
 
-				/* make StringInfo fully valid */
-				value->len = len;
-				value->cursor = 0;
-				value->maxlen = len;
+				initStringInfoFromString(value, buff, len);
 				break;
 			default:
 				elog(ERROR, "unrecognized data representation type '%c'", kind);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 597947410f..b574188d70 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3582,10 +3582,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
 
-					s.data = buf;
-					s.len = len;
-					s.cursor = 0;
-					s.maxlen = -1;
+					initReadOnlyStringInfo(&s, buf, len);
 
 					c = pq_getmsgbyte(&s);
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c900427ecf..7c0355cb2d 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1817,23 +1817,20 @@ exec_bind_message(StringInfo input_message)
 
 			if (!isNull)
 			{
-				const char *pvalue = pq_getmsgbytes(input_message, plength);
+				char	   *pvalue;
 
 				/*
-				 * Rather than copying data around, we just set up a phony
+				 * Rather than copying data around, we just initialize a
 				 * StringInfo pointing to the correct portion of the message
 				 * buffer.  We assume we can scribble on the message buffer so
 				 * as to maintain the convention that StringInfos have a
 				 * trailing null.  This is grotty but is a big win when
 				 * dealing with very large parameter strings.
 				 */
-				pbuf.data = unconstify(char *, pvalue);
-				pbuf.maxlen = plength + 1;
-				pbuf.len = plength;
-				pbuf.cursor = 0;
-
-				csave = pbuf.data[plength];
-				pbuf.data[plength] = '\0';
+				pvalue = unconstify(char *, pq_getmsgbytes(input_message, plength));
+				csave = pvalue[plength];
+				pvalue[plength] = '\0';
+				initReadOnlyStringInfo(&pbuf, pvalue, plength);
 			}
 			else
 			{
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index ad176651d8..a941a76ff3 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -623,21 +623,19 @@ record_recv(PG_FUNCTION_ARGS)
 		}
 		else
 		{
+			char	   *strbuff;
+
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
-			 * the convention that StringInfos have a trailing null.
+			 * Initialize a new StringInfo using the correct portion of the
+			 * input buffer.  We assume we can scribble on the input buffer so
+			 * as to maintain the convention that StringInfos have a trailing
+			 * null.
 			 */
-			item_buf.data = &buf->data[buf->cursor];
-			item_buf.maxlen = itemlen + 1;
-			item_buf.len = itemlen;
-			item_buf.cursor = 0;
-
+			strbuff = &buf->data[buf->cursor];
 			buf->cursor += itemlen;
-
 			csave = buf->data[buf->cursor];
 			buf->data[buf->cursor] = '\0';
+			initReadOnlyStringInfo(&item_buf, strbuff, itemlen);
 
 			bufptr = &item_buf;
 			nulls[i] = false;
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..a6a05e2f91 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -70,10 +70,16 @@ initStringInfo(StringInfo str)
  *
  * Reset the StringInfo: the data buffer remains valid, but its
  * previous content, if any, is cleared.
+ *
+ * Read-only StringInfos as initialized by initReadOnlyStringInfo cannot be
+ * reset.
  */
 void
 resetStringInfo(StringInfo str)
 {
+	/* Don't allow resets of read-only StringInfos */
+	Assert(str->maxlen != 0);
+
 	str->data[0] = '\0';
 	str->len = 0;
 	str->cursor = 0;
@@ -284,6 +290,9 @@ enlargeStringInfo(StringInfo str, int needed)
 {
 	int			newlen;
 
+	/* Validate this is not a read-only StringInfo */
+	Assert(str->maxlen != 0);
+
 	/*
 	 * Guard against out-of-range "needed" values.  Without this, we can get
 	 * an overflow or infinite loop in the following.
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..184fc1d522 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -27,10 +27,18 @@
  *		maxlen	is the allocated size in bytes of 'data', i.e. the maximum
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
- *				more space.  We must always have maxlen > len.
- *		cursor	is initialized to zero by makeStringInfo or initStringInfo,
- *				but is not otherwise touched by the stringinfo.c routines.
- *				Some routines use it to scan through a StringInfo.
+ *				more space.  We must always have maxlen > len, except
+ *				in the read-only case described below.
+ *		cursor	is initialized to zero by makeStringInfo, initStringInfo,
+ *				initReadOnlyStringInfo and initStringInfoFromString but is not
+ *				otherwise touched by the stringinfo.c routines.  Some routines
+ *				use it to scan through a StringInfo.
+ *
+ * As a special case, a StringInfoData can be initialized with a read-only
+ * string buffer.  In this case "data" does not necessarily point at a
+ * palloc'd chunk, and management of the buffer storage is the caller's
+ * responsibility.  maxlen is set to zero to indicate that this is the case.
+ * Read-only StringInfoDatas cannot be appended to or reset.
  *-------------------------
  */
 typedef struct StringInfoData
@@ -45,7 +53,7 @@ typedef StringInfoData *StringInfo;
 
 
 /*------------------------
- * There are two ways to create a StringInfo object initially:
+ * There are four ways to create a StringInfo object initially:
  *
  * StringInfo stringptr = makeStringInfo();
  *		Both the StringInfoData and the data buffer are palloc'd.
@@ -56,8 +64,31 @@ typedef StringInfoData *StringInfo;
  *		This is the easiest approach for a StringInfo object that will
  *		only live as long as the current routine.
  *
+ * StringInfoData string;
+ * initReadOnlyStringInfo(&string, existingbuf, len);
+ *		The StringInfoData's data field is set to point directly to the
+ *		existing buffer and the StringInfoData's len is set to the given len.
+ *		The given buffer can point to memory that's not managed by palloc or
+ *		is pointing partway through a palloc'd chunk.  The maxlen field is set
+ *		to 0.  A read-only StringInfo cannot be appended to using any of the
+ *		appendStringInfo functions or reset with resetStringInfo().  The given
+ *		buffer must be NUL-terminated.
+ *
+ * StringInfoData string;
+ * initStringInfoFromString(&string, palloced_buf, len);
+ *		The StringInfoData's data field is set to point directly to the given
+ *		buffer and the StringInfoData's len is set to the given len.  This
+ *		method of initialization is useful when the buffer already exists.
+ *		StringInfos initialized this way can be appended to using the
+ *		appendStringInfo functions and reset with resetStringInfo().  The
+ *		given buffer must be NUL-terminated.  The palloc'd buffer is assumed
+ *		to be len + 1 in size.
+ *
  * To destroy a StringInfo, pfree() the data buffer, and then pfree() the
  * StringInfoData if it was palloc'd.  There's no special support for this.
+ * However, if the StringInfo was initialized using initReadOnlyStringInfo()
+ * then the caller will need to consider if it is safe to pfree the data
+ * buffer.
  *
  * NOTE: some routines build up a string using StringInfo, and then
  * release the StringInfoData but return the data string itself to their
@@ -79,6 +110,49 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initReadOnlyStringInfo
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  The caller is responsible for ensuring the given string
+ * remains valid as long as the StringInfoData does.  The given string must be
+ * NUL terminated at 'len' bytes.  Calls to this are used in performance
+ * critical locations where allocating a new buffer and copying would be too
+ * costly.  Read-only StringInfoData's may not be appended to using any of the
+ * appendStringInfo functions or reset with resetStringInfo().
+ *
+ * 'data' does not need to point directly to a palloc'd chunk of memory.
+ */
+static inline void
+initReadOnlyStringInfo(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->len = len;
+	str->maxlen = 0;			/* read-only */
+	str->cursor = 0;
+}
+
+/*------------------------
+ * initStringInfoFromString
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  'data' must be a valid palloc'd chunk of memory that can have
+ * repalloc() called should more space be required during a call to any of the
+ * appendStringInfo functions.
+ *
+ * 'data' must be NUL terminated at 'len' bytes.
+ */
+static inline void
+initStringInfoFromString(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->len = len;
+	str->maxlen = len + 1;
+	str->cursor = 0;
+}
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
#20David Rowley
dgrowleyml@gmail.com
In reply to: David Rowley (#19)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Tue, 17 Oct 2023 at 20:39, David Rowley <dgrowleyml@gmail.com> wrote:

On Mon, 16 Oct 2023 at 05:56, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I guess the next question is whether we want to stop here or
try to relax the requirement about NUL-termination. I'd be inclined
to call that a separate issue deserving a separate commit, so maybe
we should go ahead and commit this much anyway.

I am keen to see this relaxed. I agree that a separate effort is best.

I looked at the latest posted patch again today with thoughts about
pushing it but there's something I'm a bit unhappy with that makes me
think we should maybe do the NUL-termination relaxation in the same
commit.

The problem is in LogicalRepApplyLoop() the current patch adjusts the
manual building of the StringInfoData to make use of
initReadOnlyStringInfo() instead. The problem I have with that is that
the string that's given to initReadOnlyStringInfo() comes from
walrcv_receive() and on looking at the API spec for walrcv_receive_fn
I see:

/*
* walrcv_receive_fn
*
* Receive a message available from the WAL stream. 'buffer' is a pointer
* to a buffer holding the message received. Returns the length of the data,
* 0 if no data is available yet ('wait_fd' is a socket descriptor which can
* be waited on before a retry), and -1 if the cluster ended the COPY.
*/

i.e, no mention that the buffer will be NUL terminated upon return.

Looking at pqGetCopyData3(), is see the buffer does get NUL
terminated, but without the API spec mentioning this I'm not feeling
good about going ahead with wrapping that up in
initReadOnlyStringInfo() which Asserts the buffer will be NUL
terminated.

I've attached a patch which builds on the previous patch and relaxes
the rule that the StringInfo must be NUL-terminated. The rule is
only relaxed for StringInfos that are initialized with
initReadOnlyStringInfo. On working on this I went over the locations
where we've added code to add a '\0' char to the buffer. If you look
at, for example, record_recv() and array_agg_deserialize() in master,
we modify the StringInfo's data to set a \0 at the end of the string.
I've removed that code as I *believe* this isn't required for the
type's receive function.

There's also an existing confusing comment in logicalrep_read_tuple()
which seems to think we're just setting the NUL terminator to conform
to StringInfo's practises. This is misleading as the NUL is required
for LOGICALREP_COLUMN_TEXT mode as we use the type's input function
instead of the receive function. You don't have to look very hard to
find an input function that needs a NUL terminator.

I'm a bit less confident that the type's receive function will never
need to be NUL terminated. cstring_recv() came to mind as one I should
look at, but on looking I see it's not required as it just reads the
remaining bytes from the input StringInfo. Is it safe to assume this?
or could there be some UDF receive function which requires this?

David

Attachments:

stringinfo_changes_v5.patchtext/plain; charset=US-ASCII; name=stringinfo_changes_v5.patchDownload
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 82f48a488e..9b37736f8e 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -774,10 +774,7 @@ LogicalParallelApplyLoop(shm_mq_handle *mqh)
 			if (len == 0)
 				elog(ERROR, "invalid message length");
 
-			s.cursor = 0;
-			s.maxlen = -1;
-			s.data = (char *) data;
-			s.len = len;
+			initReadOnlyStringInfo(&s, data, len);
 
 			/*
 			 * The first byte of messages sent from leader apply worker to
diff --git a/src/backend/replication/logical/proto.c b/src/backend/replication/logical/proto.c
index d52c8963eb..4eaeb14148 100644
--- a/src/backend/replication/logical/proto.c
+++ b/src/backend/replication/logical/proto.c
@@ -879,6 +879,7 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 	/* Read the data */
 	for (i = 0; i < natts; i++)
 	{
+		char	   *buff;
 		char		kind;
 		int			len;
 		StringInfo	value = &tuple->colvalues[i];
@@ -899,19 +900,18 @@ logicalrep_read_tuple(StringInfo in, LogicalRepTupleData *tuple)
 				len = pq_getmsgint(in, 4);	/* read length */
 
 				/* and data */
-				value->data = palloc(len + 1);
-				pq_copymsgbytes(in, value->data, len);
+				buff = palloc(len + 1);
+				pq_copymsgbytes(in, buff, len);
 
 				/*
-				 * Not strictly necessary for LOGICALREP_COLUMN_BINARY, but
-				 * per StringInfo practice.
+				 * NUL termination is required for LOGICALREP_COLUMN_TEXT mode
+				 * as input function require that.  For
+				 * LOGICALREP_COLUMN_BINARY it's not technically required, but
+				 * it's harmless.
 				 */
-				value->data[len] = '\0';
+				buff[len] = '\0';
 
-				/* make StringInfo fully valid */
-				value->len = len;
-				value->cursor = 0;
-				value->maxlen = len;
+				initStringInfoFromString(value, buff, len);
 				break;
 			default:
 				elog(ERROR, "unrecognized data representation type '%c'", kind);
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 54c14495be..567485c4a4 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -3582,10 +3582,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
 
-					s.data = buf;
-					s.len = len;
-					s.cursor = 0;
-					s.maxlen = -1;
+					initReadOnlyStringInfo(&s, buf, len);
 
 					c = pq_getmsgbyte(&s);
 
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index c900427ecf..cb68b8efaf 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -1817,23 +1817,18 @@ exec_bind_message(StringInfo input_message)
 
 			if (!isNull)
 			{
-				const char *pvalue = pq_getmsgbytes(input_message, plength);
+				char	   *pvalue;
 
 				/*
-				 * Rather than copying data around, we just set up a phony
+				 * Rather than copying data around, we just initialize a
 				 * StringInfo pointing to the correct portion of the message
-				 * buffer.  We assume we can scribble on the message buffer so
-				 * as to maintain the convention that StringInfos have a
-				 * trailing null.  This is grotty but is a big win when
-				 * dealing with very large parameter strings.
+				 * buffer.  We must NUL terminate the string for the sake of
+				 * the input function call below.
 				 */
-				pbuf.data = unconstify(char *, pvalue);
-				pbuf.maxlen = plength + 1;
-				pbuf.len = plength;
-				pbuf.cursor = 0;
-
-				csave = pbuf.data[plength];
-				pbuf.data[plength] = '\0';
+				pvalue = unconstify(char *, pq_getmsgbytes(input_message, plength));
+				csave = pvalue[plength];
+				pvalue[plength] = '\0';
+				initReadOnlyStringInfo(&pbuf, pvalue, plength);
 			}
 			else
 			{
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index 5c4fdcfba4..c831a9395c 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -784,7 +784,6 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 		{
 			int			itemlen;
 			StringInfoData elem_buf;
-			char		csave;
 
 			if (result->dnulls[i])
 			{
@@ -799,28 +798,19 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 						 errmsg("insufficient data left in message")));
 
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
-			 * the convention that StringInfos have a trailing null.
+			 * Rather than copying data around, we just initialize a
+			 * StringInfo pointing to the correct portion of the message
+			 * buffer.
 			 */
-			elem_buf.data = &buf.data[buf.cursor];
-			elem_buf.maxlen = itemlen + 1;
-			elem_buf.len = itemlen;
-			elem_buf.cursor = 0;
+			initReadOnlyStringInfo(&elem_buf, &buf.data[buf.cursor], itemlen);
 
 			buf.cursor += itemlen;
 
-			csave = buf.data[buf.cursor];
-			buf.data[buf.cursor] = '\0';
-
 			/* Now call the element's receiveproc */
 			result->dvalues[i] = ReceiveFunctionCall(&iodata->typreceive,
 													 &elem_buf,
 													 iodata->typioparam,
 													 -1);
-
-			buf.data[buf.cursor] = csave;
 		}
 	}
 
diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c
index 7828a6264b..6a920a02b7 100644
--- a/src/backend/utils/adt/arrayfuncs.c
+++ b/src/backend/utils/adt/arrayfuncs.c
@@ -1475,7 +1475,6 @@ ReadArrayBinary(StringInfo buf,
 	{
 		int			itemlen;
 		StringInfoData elem_buf;
-		char		csave;
 
 		/* Get and check the item length */
 		itemlen = pq_getmsgint(buf, 4);
@@ -1494,21 +1493,13 @@ ReadArrayBinary(StringInfo buf,
 		}
 
 		/*
-		 * Rather than copying data around, we just set up a phony StringInfo
-		 * pointing to the correct portion of the input buffer. We assume we
-		 * can scribble on the input buffer so as to maintain the convention
-		 * that StringInfos have a trailing null.
+		 * Rather than copying data around, we just initialize a StringInfo
+		 * pointing to the correct portion of the message buffer.
 		 */
-		elem_buf.data = &buf->data[buf->cursor];
-		elem_buf.maxlen = itemlen + 1;
-		elem_buf.len = itemlen;
-		elem_buf.cursor = 0;
+		initReadOnlyStringInfo(&elem_buf, &buf->data[buf->cursor], itemlen);
 
 		buf->cursor += itemlen;
 
-		csave = buf->data[buf->cursor];
-		buf->data[buf->cursor] = '\0';
-
 		/* Now call the element's receiveproc */
 		values[i] = ReceiveFunctionCall(receiveproc, &elem_buf,
 										typioparam, typmod);
@@ -1520,8 +1511,6 @@ ReadArrayBinary(StringInfo buf,
 					(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 					 errmsg("improper binary format in array element %d",
 							i + 1)));
-
-		buf->data[buf->cursor] = csave;
 	}
 
 	/*
diff --git a/src/backend/utils/adt/rowtypes.c b/src/backend/utils/adt/rowtypes.c
index ad176651d8..eb8fe95933 100644
--- a/src/backend/utils/adt/rowtypes.c
+++ b/src/backend/utils/adt/rowtypes.c
@@ -569,7 +569,6 @@ record_recv(PG_FUNCTION_ARGS)
 		int			itemlen;
 		StringInfoData item_buf;
 		StringInfo	bufptr;
-		char		csave;
 
 		/* Ignore dropped columns in datatype, but fill with nulls */
 		if (att->attisdropped)
@@ -619,25 +618,19 @@ record_recv(PG_FUNCTION_ARGS)
 			/* -1 length means NULL */
 			bufptr = NULL;
 			nulls[i] = true;
-			csave = 0;			/* keep compiler quiet */
 		}
 		else
 		{
+			char	   *strbuff;
+
 			/*
-			 * Rather than copying data around, we just set up a phony
-			 * StringInfo pointing to the correct portion of the input buffer.
-			 * We assume we can scribble on the input buffer so as to maintain
-			 * the convention that StringInfos have a trailing null.
+			 * Rather than copying data around, we just initialize a
+			 * StringInfo pointing to the correct portion of the message
+			 * buffer.
 			 */
-			item_buf.data = &buf->data[buf->cursor];
-			item_buf.maxlen = itemlen + 1;
-			item_buf.len = itemlen;
-			item_buf.cursor = 0;
-
+			strbuff = &buf->data[buf->cursor];
 			buf->cursor += itemlen;
-
-			csave = buf->data[buf->cursor];
-			buf->data[buf->cursor] = '\0';
+			initReadOnlyStringInfo(&item_buf, strbuff, itemlen);
 
 			bufptr = &item_buf;
 			nulls[i] = false;
@@ -667,8 +660,6 @@ record_recv(PG_FUNCTION_ARGS)
 						(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 						 errmsg("improper binary format in record column %d",
 								i + 1)));
-
-			buf->data[buf->cursor] = csave;
 		}
 	}
 
diff --git a/src/common/stringinfo.c b/src/common/stringinfo.c
index 05b22b5c53..dc97754a68 100644
--- a/src/common/stringinfo.c
+++ b/src/common/stringinfo.c
@@ -70,10 +70,16 @@ initStringInfo(StringInfo str)
  *
  * Reset the StringInfo: the data buffer remains valid, but its
  * previous content, if any, is cleared.
+ *
+ * Read-only StringInfos as initialized by initReadOnlyStringInfo cannot be
+ * reset.
  */
 void
 resetStringInfo(StringInfo str)
 {
+	/* don't allow resets of read-only StringInfos */
+	Assert(str->maxlen != 0);
+
 	str->data[0] = '\0';
 	str->len = 0;
 	str->cursor = 0;
@@ -284,6 +290,9 @@ enlargeStringInfo(StringInfo str, int needed)
 {
 	int			newlen;
 
+	/* validate this is not a read-only StringInfo */
+	Assert(str->maxlen != 0);
+
 	/*
 	 * Guard against out-of-range "needed" values.  Without this, we can get
 	 * an overflow or infinite loop in the following.
diff --git a/src/include/lib/stringinfo.h b/src/include/lib/stringinfo.h
index 36a416f8e0..019129a6d3 100644
--- a/src/include/lib/stringinfo.h
+++ b/src/include/lib/stringinfo.h
@@ -20,17 +20,25 @@
 
 /*-------------------------
  * StringInfoData holds information about an extensible string.
- *		data	is the current buffer for the string (allocated with palloc).
- *		len		is the current string length.  There is guaranteed to be
- *				a terminating '\0' at data[len], although this is not very
- *				useful when the string holds binary data rather than text.
+ *		data	is the current buffer for the string.
+ *		len		is the current string length.  Except in the case of read-only
+ *				strings described below, there is guaranteed to be a
+ *				terminating '\0' at data[len].
  *		maxlen	is the allocated size in bytes of 'data', i.e. the maximum
  *				string size (including the terminating '\0' char) that we can
  *				currently store in 'data' without having to reallocate
- *				more space.  We must always have maxlen > len.
- *		cursor	is initialized to zero by makeStringInfo or initStringInfo,
- *				but is not otherwise touched by the stringinfo.c routines.
- *				Some routines use it to scan through a StringInfo.
+ *				more space.  We must always have maxlen > len, except
+ *				in the read-only case described below.
+ *		cursor	is initialized to zero by makeStringInfo, initStringInfo,
+ *				initReadOnlyStringInfo and initStringInfoFromString but is not
+ *				otherwise touched by the stringinfo.c routines.  Some routines
+ *				use it to scan through a StringInfo.
+ *
+ * As a special case, a StringInfoData can be initialized with a read-only
+ * string buffer.  In this case "data" does not necessarily point at a
+ * palloc'd chunk, and management of the buffer storage is the caller's
+ * responsibility.  maxlen is set to zero to indicate that this is the case.
+ * Read-only StringInfoDatas cannot be appended to or reset.
  *-------------------------
  */
 typedef struct StringInfoData
@@ -45,7 +53,7 @@ typedef StringInfoData *StringInfo;
 
 
 /*------------------------
- * There are two ways to create a StringInfo object initially:
+ * There are four ways to create a StringInfo object initially:
  *
  * StringInfo stringptr = makeStringInfo();
  *		Both the StringInfoData and the data buffer are palloc'd.
@@ -56,8 +64,31 @@ typedef StringInfoData *StringInfo;
  *		This is the easiest approach for a StringInfo object that will
  *		only live as long as the current routine.
  *
+ * StringInfoData string;
+ * initReadOnlyStringInfo(&string, existingbuf, len);
+ *		The StringInfoData's data field is set to point directly to the
+ *		existing buffer and the StringInfoData's len is set to the given len.
+ *		The given buffer can point to memory that's not managed by palloc or
+ *		is pointing partway through a palloc'd chunk.  The maxlen field is set
+ *		to 0.  A read-only StringInfo cannot be appended to using any of the
+ *		appendStringInfo functions or reset with resetStringInfo().  The given
+ *		buffer can optionally omit the NUL termination character.
+ *
+ * StringInfoData string;
+ * initStringInfoFromString(&string, palloced_buf, len);
+ *		The StringInfoData's data field is set to point directly to the given
+ *		buffer and the StringInfoData's len is set to the given len.  This
+ *		method of initialization is useful when the buffer already exists.
+ *		StringInfos initialized this way can be appended to using the
+ *		appendStringInfo functions and reset with resetStringInfo().  The
+ *		given buffer must be NUL-terminated.  The palloc'd buffer is assumed
+ *		to be len + 1 in size.
+ *
  * To destroy a StringInfo, pfree() the data buffer, and then pfree() the
  * StringInfoData if it was palloc'd.  There's no special support for this.
+ * However, if the StringInfo was initialized using initReadOnlyStringInfo()
+ * then the caller will need to consider if it is safe to pfree the data
+ * buffer.
  *
  * NOTE: some routines build up a string using StringInfo, and then
  * release the StringInfoData but return the data string itself to their
@@ -79,6 +110,48 @@ extern StringInfo makeStringInfo(void);
  */
 extern void initStringInfo(StringInfo str);
 
+/*------------------------
+ * initReadOnlyStringInfo
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  The caller is responsible for ensuring the given string
+ * remains valid as long as the StringInfoData does.  Calls to this are used
+ * in performance critical locations where allocating a new buffer and copying
+ * would be too costly.  Read-only StringInfoData's may not be appended to
+ * using any of the appendStringInfo functions or reset with
+ * resetStringInfo().
+ *
+ * 'data' does not need to point directly to a palloc'd chunk of memory and may
+ * omit the NUL termination character at data[len].
+ */
+static inline void
+initReadOnlyStringInfo(StringInfo str, char *data, int len)
+{
+	str->data = data;
+	str->len = len;
+	str->maxlen = 0;			/* read-only */
+	str->cursor = 0;
+}
+
+/*------------------------
+ * initStringInfoFromString
+ * Initialize a StringInfoData struct from an existing string without copying
+ * the string.  'data' must be a valid palloc'd chunk of memory that can have
+ * repalloc() called should more space be required during a call to any of the
+ * appendStringInfo functions.
+ *
+ * 'data' must be NUL terminated at 'len' bytes.
+ */
+static inline void
+initStringInfoFromString(StringInfo str, char *data, int len)
+{
+	Assert(data[len] == '\0');
+
+	str->data = data;
+	str->len = len;
+	str->maxlen = len + 1;
+	str->cursor = 0;
+}
+
 /*------------------------
  * resetStringInfo
  * Clears the current content of the StringInfo, if any. The
#21Tom Lane
tgl@sss.pgh.pa.us
In reply to: David Rowley (#20)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

David Rowley <dgrowleyml@gmail.com> writes:

I've attached a patch which builds on the previous patch and relaxes
the rule that the StringInfo must be NUL-terminated. The rule is
only relaxed for StringInfos that are initialized with
initReadOnlyStringInfo.

Yeah, that's probably a reasonable way to frame it.

There's also an existing confusing comment in logicalrep_read_tuple()
which seems to think we're just setting the NUL terminator to conform
to StringInfo's practises. This is misleading as the NUL is required
for LOGICALREP_COLUMN_TEXT mode as we use the type's input function
instead of the receive function. You don't have to look very hard to
find an input function that needs a NUL terminator.

Right, input functions are likely to expect this.

I'm a bit less confident that the type's receive function will never
need to be NUL terminated. cstring_recv() came to mind as one I should
look at, but on looking I see it's not required as it just reads the
remaining bytes from the input StringInfo. Is it safe to assume this?

I think that we can make that assumption starting with v17.
Back-patching it would be hazardous perhaps; but if there's some
function out there that depends on NUL termination, testing should
expose it before too long. Wouldn't hurt to mention this explicitly
as a possible incompatibility in the commit message.

Looking over the v5 patch, I have some nits:

* In logicalrep_read_tuple,
s/input function require that/input functions require that/
(or fix the grammatical disagreement some other way)

* In exec_bind_message, you removed the comment pointing out that
we are scribbling directly on the message buffer, even though
we still are. This patch does nothing to make that any safer,
so I object to removing the comment.

* In stringinfo.h, I'd suggest adding text more or less like this
within or at the end of the "As a special case, ..." para in
the first large comment block:

* Also, it is caller's option whether a read-only string buffer has
* a terminating '\0' or not. This depends on the intended usage.

That's partially redundant with some other comments, but this para
is defining the API for read-only buffers, so I think it would
be good to include it here.

regards, tom lane

#22David Rowley
dgrowleyml@gmail.com
In reply to: Tom Lane (#21)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Thu, 26 Oct 2023 at 08:43, Tom Lane <tgl@sss.pgh.pa.us> wrote:

I think that we can make that assumption starting with v17.
Back-patching it would be hazardous perhaps; but if there's some
function out there that depends on NUL termination, testing should
expose it before too long. Wouldn't hurt to mention this explicitly
as a possible incompatibility in the commit message.

Looking over the v5 patch, I have some nits:

Thanks for looking at this again. I fixed up each of those and pushed
the result, mentioning the incompatibility in the commit message.

Now that that's done, I've attached a patch which makes use of the new
initReadOnlyStringInfo initializer function for the original case
mentioned when I opened this thread. I don't think there are any
remaining objections to this, but I'll let it sit for a bit to see.

David

Attachments:

use_initReadOnlyStringInfo_more.patchtext/plain; charset=US-ASCII; name=use_initReadOnlyStringInfo_more.patchDownload
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index c831a9395c..57bd7e82bc 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -723,12 +723,11 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -815,7 +814,6 @@ array_agg_deserialize(PG_FUNCTION_ARGS)
 	}
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
@@ -1124,12 +1122,11 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	/* element_type */
 	element_type = pq_getmsgint(&buf, 4);
@@ -1187,7 +1184,6 @@ array_agg_array_deserialize(PG_FUNCTION_ARGS)
 	memcpy(result->lbs, temp, sizeof(result->lbs));
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 3c3184f15b..bf61fd7dbc 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -5190,12 +5190,11 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5222,7 +5221,6 @@ numeric_avg_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5306,12 +5304,11 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeNumericAggStateCurrentContext(false);
 
@@ -5342,7 +5339,6 @@ numeric_deserialize(PG_FUNCTION_ARGS)
 	result->nInfcount = pq_getmsgint64(&buf);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5677,12 +5673,11 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5706,7 +5701,6 @@ numeric_poly_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
@@ -5868,12 +5862,11 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 	init_var(&tmp_var);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	result = makePolyNumAggStateCurrentContext(false);
 
@@ -5889,7 +5882,6 @@ int8_avg_deserialize(PG_FUNCTION_ARGS)
 #endif
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	free_var(&tmp_var);
 
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index 72e1e24fe0..ec4e580d7f 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -5289,12 +5289,11 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	sstate = PG_GETARG_BYTEA_PP(0);
 
 	/*
-	 * Copy the bytea into a StringInfo so that we can "receive" it using the
-	 * standard recv-function infrastructure.
+	 * Initialize a StringInfo so that we can "receive" it using the standard
+	 * recv-function infrastructure.
 	 */
-	initStringInfo(&buf);
-	appendBinaryStringInfo(&buf,
-						   VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
+	initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
+						   VARSIZE_ANY_EXHDR(sstate));
 
 	result = makeStringAggState(fcinfo);
 
@@ -5307,7 +5306,6 @@ string_agg_deserialize(PG_FUNCTION_ARGS)
 	appendBinaryStringInfo(result, data, datalen);
 
 	pq_getmsgend(&buf);
-	pfree(buf.data);
 
 	PG_RETURN_POINTER(result);
 }
#23David Rowley
dgrowleyml@gmail.com
In reply to: David Rowley (#22)
1 attachment(s)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Thu, 26 Oct 2023 at 17:00, David Rowley <dgrowleyml@gmail.com> wrote:

Thanks for looking at this again. I fixed up each of those and pushed
the result, mentioning the incompatibility in the commit message.

Now that that's done, I've attached a patch which makes use of the new
initReadOnlyStringInfo initializer function for the original case
mentioned when I opened this thread. I don't think there are any
remaining objections to this, but I'll let it sit for a bit to see.

I've just pushed the deserial function optimisation patch.

I was just looking at a few other places where we might want to make
use of initReadOnlyStringInfo.

* parallel.c in HandleParallelMessages():

Drilling into HandleParallelMessage(), I see the PqMsg_BackendKeyData
case just reads a fixed number of bytes. In some of the other
"switch" cases, I see calls pq_getmsgrawstring() either directly or
indirectly. I see the counterpart to pq_getmsgrawstring() is
pq_sendstring() which always appends the NUL char to the StringInfo,
so I don't think not NUL terminating the received bytes is a problem
as cstrings seem to be sent with the NUL terminator.

This case just seems to handle ERROR/NOTICE messages coming from
parallel workers. Not tuples themselves. It may not be that
interesting a case to speed up.

* applyparallelworker.c in HandleParallelApplyMessages():

Drilling into HandleParallelApplyMessage(), I don't see anything there
that needs the input StringInfo to be NUL terminated.

* worker.c in apply_spooled_messages():

Drilling into apply_dispatch() and going through each of the cases, I
see logicalrep_read_tuple() pallocs a new buffer and ensures it's
always NUL terminated which will be required in LOGICALREP_COLUMN_TEXT
mode. (There seems to be further optimisation opportunities there
where we could not do the palloc when in LOGICALREP_COLUMN_BINARY mode
and just point value's buffer directly to the correct portion of the
input StringInfo's buffer).

* walreceiver.c in XLogWalRcvProcessMsg():

Nothing there seems to require the incoming_message StringInfo to have
a NUL terminator. I imagine this one is the most worthwhile to do out
of the 4. I've not tested to see if there are any performance
improvements.

Does anyone see any reason why we can't do the attached?

David

Attachments:

use_initReadOnlyStringInfo_even_more.patchtext/plain; charset=US-ASCII; name=use_initReadOnlyStringInfo_even_more.patchDownload
diff --git a/src/backend/access/transam/parallel.c b/src/backend/access/transam/parallel.c
index 194a1207be..f3708005d2 100644
--- a/src/backend/access/transam/parallel.c
+++ b/src/backend/access/transam/parallel.c
@@ -1087,10 +1087,8 @@ HandleParallelMessages(void)
 				{
 					StringInfoData msg;
 
-					initStringInfo(&msg);
-					appendBinaryStringInfo(&msg, data, nbytes);
+					initReadOnlyStringInfo(&msg, data, nbytes);
 					HandleParallelMessage(pcxt, i, &msg);
-					pfree(msg.data);
 				}
 				else
 					ereport(ERROR,
diff --git a/src/backend/replication/logical/applyparallelworker.c b/src/backend/replication/logical/applyparallelworker.c
index 9b37736f8e..fcc33bda10 100644
--- a/src/backend/replication/logical/applyparallelworker.c
+++ b/src/backend/replication/logical/applyparallelworker.c
@@ -1117,10 +1117,8 @@ HandleParallelApplyMessages(void)
 		{
 			StringInfoData msg;
 
-			initStringInfo(&msg);
-			appendBinaryStringInfo(&msg, data, nbytes);
+			initReadOnlyStringInfo(&msg, data, nbytes);
 			HandleParallelApplyMessage(&msg);
-			pfree(msg.data);
 		}
 		else
 			ereport(ERROR,
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index ba67eb156f..52a9f136ab 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -2019,7 +2019,6 @@ void
 apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
 					   XLogRecPtr lsn)
 {
-	StringInfoData s2;
 	int			nchanges;
 	char		path[MAXPGPATH];
 	char	   *buffer = NULL;
@@ -2057,7 +2056,6 @@ apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
 	CurrentResourceOwner = oldowner;
 
 	buffer = palloc(BLCKSZ);
-	initStringInfo(&s2);
 
 	MemoryContextSwitchTo(oldcxt);
 
@@ -2079,6 +2077,7 @@ apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
 	nchanges = 0;
 	while (true)
 	{
+		StringInfoData s2;
 		size_t		nbytes;
 		int			len;
 
@@ -2104,9 +2103,8 @@ apply_spooled_messages(FileSet *stream_fileset, TransactionId xid,
 
 		BufFileTell(stream_fd, &fileno, &offset);
 
-		/* copy the buffer to the stringinfo and call apply_dispatch */
-		resetStringInfo(&s2);
-		appendBinaryStringInfo(&s2, buffer, len);
+		/* init a stringinfo using the buffer and call apply_dispatch */
+		initReadOnlyStringInfo(&s2, buffer, len);
 
 		/* Ensure we are reading the data into our memory context. */
 		oldcxt = MemoryContextSwitchTo(ApplyMessageContext);
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index a3128874b2..2398167f49 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -132,7 +132,6 @@ typedef enum WalRcvWakeupReason
 static TimestampTz wakeup[NUM_WALRCV_WAKEUPS];
 
 static StringInfoData reply_message;
-static StringInfoData incoming_message;
 
 /* Prototypes for private functions */
 static void WalRcvFetchTimeLineHistoryFiles(TimeLineID first, TimeLineID last);
@@ -425,7 +424,6 @@ WalReceiverMain(void)
 			/* Initialize LogstreamResult and buffers for processing messages */
 			LogstreamResult.Write = LogstreamResult.Flush = GetXLogReplayRecPtr(NULL);
 			initStringInfo(&reply_message);
-			initStringInfo(&incoming_message);
 
 			/* Initialize nap wakeup times. */
 			now = GetCurrentTimestamp();
@@ -843,19 +841,20 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
 	TimestampTz sendTime;
 	bool		replyRequested;
 
-	resetStringInfo(&incoming_message);
-
 	switch (type)
 	{
 		case 'w':				/* WAL records */
 			{
-				/* copy message to StringInfo */
+				StringInfoData incoming_message;
+
 				hdrlen = sizeof(int64) + sizeof(int64) + sizeof(int64);
 				if (len < hdrlen)
 					ereport(ERROR,
 							(errcode(ERRCODE_PROTOCOL_VIOLATION),
 							 errmsg_internal("invalid WAL message received from primary")));
-				appendBinaryStringInfo(&incoming_message, buf, hdrlen);
+
+				/* initialize a StringInfo with the given buffer */
+				initReadOnlyStringInfo(&incoming_message, buf, hdrlen);
 
 				/* read the fields */
 				dataStart = pq_getmsgint64(&incoming_message);
@@ -870,13 +869,16 @@ XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len, TimeLineID tli)
 			}
 		case 'k':				/* Keepalive */
 			{
-				/* copy message to StringInfo */
+				StringInfoData incoming_message;
+
 				hdrlen = sizeof(int64) + sizeof(int64) + sizeof(char);
 				if (len != hdrlen)
 					ereport(ERROR,
 							(errcode(ERRCODE_PROTOCOL_VIOLATION),
 							 errmsg_internal("invalid keepalive message received from primary")));
-				appendBinaryStringInfo(&incoming_message, buf, hdrlen);
+
+				/* initialize a StringInfo with the given buffer */
+				initReadOnlyStringInfo(&incoming_message, buf, hdrlen);
 
 				/* read the fields */
 				walEnd = pq_getmsgint64(&incoming_message);
#24Amit Kapila
amit.kapila16@gmail.com
In reply to: David Rowley (#23)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Fri, Oct 27, 2023 at 3:23 AM David Rowley <dgrowleyml@gmail.com> wrote:

On Thu, 26 Oct 2023 at 17:00, David Rowley <dgrowleyml@gmail.com> wrote:

Thanks for looking at this again. I fixed up each of those and pushed
the result, mentioning the incompatibility in the commit message.

Now that that's done, I've attached a patch which makes use of the new
initReadOnlyStringInfo initializer function for the original case
mentioned when I opened this thread. I don't think there are any
remaining objections to this, but I'll let it sit for a bit to see.

I've just pushed the deserial function optimisation patch.

I was just looking at a few other places where we might want to make
use of initReadOnlyStringInfo.

* parallel.c in HandleParallelMessages():

Drilling into HandleParallelMessage(), I see the PqMsg_BackendKeyData
case just reads a fixed number of bytes. In some of the other
"switch" cases, I see calls pq_getmsgrawstring() either directly or
indirectly. I see the counterpart to pq_getmsgrawstring() is
pq_sendstring() which always appends the NUL char to the StringInfo,
so I don't think not NUL terminating the received bytes is a problem
as cstrings seem to be sent with the NUL terminator.

This case just seems to handle ERROR/NOTICE messages coming from
parallel workers. Not tuples themselves. It may not be that
interesting a case to speed up.

* applyparallelworker.c in HandleParallelApplyMessages():

Drilling into HandleParallelApplyMessage(), I don't see anything there
that needs the input StringInfo to be NUL terminated.

Both the above calls are used to handle ERROR/NOTICE messages from
parallel workers as you have also noticed. The comment atop
initReadOnlyStringInfo() clearly states that it is used in the
performance-critical path. So, is it worth changing these places? In
the future, this may pose the risk of this API being used
inconsistently.

--
With Regards,
Amit Kapila.

#25David Rowley
dgrowleyml@gmail.com
In reply to: Amit Kapila (#24)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Mon, 30 Oct 2023 at 23:48, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Oct 27, 2023 at 3:23 AM David Rowley <dgrowleyml@gmail.com> wrote:

* parallel.c in HandleParallelMessages():
* applyparallelworker.c in HandleParallelApplyMessages():

Both the above calls are used to handle ERROR/NOTICE messages from
parallel workers as you have also noticed. The comment atop
initReadOnlyStringInfo() clearly states that it is used in the
performance-critical path. So, is it worth changing these places? In
the future, this may pose the risk of this API being used
inconsistently.

I'm ok to leave those ones out. But just a note on the performance
side, if we go around needlessly doing palloc/memcpy then we'll be
flushing possibly useful cachelines out and cause slowdowns elsewhere.
That's a pretty hard thing to quantify, but something to keep in mind.

David

#26Amit Kapila
amit.kapila16@gmail.com
In reply to: David Rowley (#25)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Tue, Oct 31, 2023 at 2:25 AM David Rowley <dgrowleyml@gmail.com> wrote:

On Mon, 30 Oct 2023 at 23:48, Amit Kapila <amit.kapila16@gmail.com> wrote:

On Fri, Oct 27, 2023 at 3:23 AM David Rowley <dgrowleyml@gmail.com> wrote:

* parallel.c in HandleParallelMessages():
* applyparallelworker.c in HandleParallelApplyMessages():

Both the above calls are used to handle ERROR/NOTICE messages from
parallel workers as you have also noticed. The comment atop
initReadOnlyStringInfo() clearly states that it is used in the
performance-critical path. So, is it worth changing these places? In
the future, this may pose the risk of this API being used
inconsistently.

I'm ok to leave those ones out.

The other two look good to me.

--
With Regards,
Amit Kapila.

#27David Rowley
dgrowleyml@gmail.com
In reply to: Amit Kapila (#26)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Thu, 2 Nov 2023 at 22:42, Amit Kapila <amit.kapila16@gmail.com> wrote:

The other two look good to me.

Thanks for looking.

I spent some time trying to see if the performance changes much with
either of these cases. For the XLogWalRcvProcessMsg() I was unable to
measure any difference even when replaying inserts into a table with a
single int4 column and no indexes. I think that change is worthwhile
regardless as it allows us to get rid of a global variable. I was
tempted to shorten the name of that variable a bit since it's now
local, but didn't as it causes a bit more churn.

For the apply_spooled_messages() change, I tried logical decoding but
quickly saw apply_spooled_messages() isn't the normal case. I didn't
quite find a test case that caused the changes to be serialized to a
file, but I do see that the number of bytes can be large so thought
that it's worthwhile saving the memcpy for that case.

I pushed those two changes.

David

#28Amit Kapila
amit.kapila16@gmail.com
In reply to: David Rowley (#27)
Re: Making aggregate deserialization (and WAL receive) functions slightly faster

On Tue, Nov 7, 2023 at 3:56 AM David Rowley <dgrowleyml@gmail.com> wrote:

On Thu, 2 Nov 2023 at 22:42, Amit Kapila <amit.kapila16@gmail.com> wrote:

The other two look good to me.

Thanks for looking.

I spent some time trying to see if the performance changes much with
either of these cases. For the XLogWalRcvProcessMsg() I was unable to
measure any difference even when replaying inserts into a table with a
single int4 column and no indexes. I think that change is worthwhile
regardless as it allows us to get rid of a global variable. I was
tempted to shorten the name of that variable a bit since it's now
local, but didn't as it causes a bit more churn.

For the apply_spooled_messages() change, I tried logical decoding but
quickly saw apply_spooled_messages() isn't the normal case. I didn't
quite find a test case that caused the changes to be serialized to a
file, but I do see that the number of bytes can be large so thought
that it's worthwhile saving the memcpy for that case.

Yeah, and another reason is that the usage of StringInfo becomes
consistent with LogicalRepApplyLoop(). One can always configure the
lower value of logical_decoding_work_mem or use
debug_logical_replication_streaming for a smaller number of changes to
follow that code path. But I am not sure how much practically it will
help because we are anyway reading file to apply the changes.

--
With Regards,
Amit Kapila.