xR4{7DApr?YmL|crf6wSEB)L z7mY~j5(IT11GxE_Qu+52qE-!LGw<)C@donXG5k7&9q8TzOhXAT3F-zUAqc>;2r&ej zK;Iw`d&cC@AHi-de`N}CnSzFB= z66dHF86DbzZVSNa5EZ74Ra3Y`g02EWlyy)yfZ&D~mwo>w_*4KzDtaCSi?R~}M!&d9 zpcteBBryw&?0b=<5dAkV3a;OoM+>I$1OB56N_6L#3u9cJzh%z9 9!QZN5NB?}%>@3P4w)E??+ _EvyCSe^huevs-)Ul7oA8fUt6qlA#Is<6&S2=cXXWuhqwXO3o=0ETxd?P5eK5x$nU3?(5h4u z2rc)K2W5svG%Y=qu2k9YrD%#SxXbw+u5JyMm2)*Ux((ak)duX2e)sS?foyfWnKj*I zj&rg^#CQ*h$NW<8^y2&4zGiGb*XzEBWLxBolyoJw?Pj1q8|rSnWyy(?j%tlLJqKy# z2Xo7XR}u2+cRXc#`{c8)Qg+WM99gwu9sM}LY^zON^FCY^9eoIE-anDDL~WJJe$tad zdfZW~>Z=6d^!$?PD~YL~aPfK3bIyegziWV_6;<|{{#|z qv-9uy}+gcf7wJ7Ej -1R zFTI#nfF|AGZ`N}cKU0(`a*w?b#N78fmkBruoF{*sAb8wa62zyFHHGzc+2lFM{@N$u z@fD8PTMWA#W(x}wV|&RyBXH`srEp*CI`^i7oFrFS)p&Wx92*(0Pp0{me_=%v*;l%J zd;6h399l~g4X7|@E!j!SmxG^BBA)F64Sl1(#5C5tH+Fsvg$ERM@Xm-LBSkd$!JG&2 zidh(Q-z_ej58VKPYWu0Kv)OWEmc~n@8_lJ~RpWB!1Pn-I`=$|VMQ=5?wtmft))5F6 zF&d1dA>2d8%(N9 ); z8QVZcg;7=!TS<6L+fC5f2nAxK9cSa8F9cj@rz%eh!Q52Gogh2GBzw1rf%}M({Scs2 zP8HnxM~iyh;3X_Volwb*We@f|g#LcTal5;9?{@m@SDCxWG^(n0sn?&IBkHihw_9FT zQ9j1A5X+XFIHQw1Qh5=W7n||%E`8J1f-d|;NNXh*pX94|{j{+>RPMX6-Xk!qM)p#K z=W1**XOaw_G`p|k>*n$xo^8JgX!p~-Y)YIlz<~z1!2=aCt)(_jFD(u^ejnwu$UN`~ zyv+7&5yrl$c0S9uu1N#Ou6HtH_nNyBQ`2wkL4KGRR0}htY4DSU`T4n*rW09FDLY>V zPXOz_b}8RW7*Xo*=G%VIn`?R^>CL~do)r$Vgse8U3bi aaKyTv$!Hgoj~Sa6s_4;JCr&82 z_@Sdq*y0j*$wa<>xBP%o=Uzo0b|$-qGCSv_y~ohp_DeZAX~!c~9M^}7%uw)r^1*Ro zftP>O-BDq4zVnvdz^&M9zsqZshZK==WV5g-oC;(6o42$iT|Exkelyv~u^55sdvxO* zCxkw9IeLl9kxp-aQi`>E&kwTokJjDf1|am*k%0
SN) zO-iI+eeq{({ef@g8{ZQM@Wuy)vPXrNEki>_^_*hJUMV)i!GdRY+A{W+!}i}1tkV^ JLWf`_2F9Hd(v0UpsAfj6w9f1z s4tsg=TEsJdM4UvPxW<{c&~B`vi>9aL<%{=MdR$ zh2>K=`+C=#>^Iu-nNmmd^R-4Uh2jo#;=Zqmm^n%BGTun1g6LaEJdKWf`SKwVHqpF@ z=qWFAl2fNn%-s1qNLIvnA40a)we-XN+H%V;lkW(PB{mI7h52gBk?Hq{(K68n&L0~N z@&sAEbxcy*orRra@Z3hE>?Y=$tp-RWBfOuA+n>`(3zgc8=^Bltq5h^POsH?KZ}XJ7 z%{XBb=v3+XvrA5oFE qaV_!A0p_c^O;Ybe zQrPv(GDn^x=(dwqnggLDWjg|09s62fjo)HiY{IxQ6w+QA&oq Us{KH?iqk9Ry+%h@!Sn-AlXt6jVwg*2=>-j}x2KBUt2AmCqgVT+uDvKT z6CS!;cXrg3^y#h9=yv7P$=9(}p3+wls-r)t)ne)OEYh2;-?q-=3viw zVV=o_mnLmQm0E8aZcL}!Lt|s2*bTeuAZGVHj@WrL>*Nj>tSxK=%pgfI6IZ@*z?h7W z!FT2gQ0GkF^2#yuZ5mRrxzpfH-5kUBVKx2XF?-Oxz&RXQD*{l#z7^!Hr}c%;l?8c( zZ)jhR2m$Oxl4?enfwwZ?YT%uJWZUAUIkd{I7|%2+Vua^OUk{5TQhE4CD~HD&^)z~M zvbjwVi~f8k%;|TGiGBzDekHL#%dRH_ePew_zV8=i?(Ycwk;zZiPtZKi9ZVJ_T}q2n zfgF?u&q!lN46E$N8JfkzDLr$v8rQ9#lSL%Rax@;#uv<^bnC}*&SjS#6yl*mCl)66d z8#xa1b5&j(DAYyQUsGcWS^zZ=gFe>iYRiwwjT>CnWFb}ma`ZuB`QxUTemQ54B$Ysz zm^gAuGr)B4+FpE_X2QblmLXtjdI&atDqpHiPHy!!4-sIT*pzTlQcXVZa2ZEA_EMFV z387k*kH< +T& z+75>IcgckN$g@d?dFiJUzTu2Nlzk1IH_fSAhsBMKHxvY4B|q&ptelum7PxAuo0&^U z_*m(MPig57AD?;I!~}>~LpPct&}SqKqWh+lX}z4`V>%FB`97l1JFOJ9AftYQw3N}| z0=EL`gFtm`FIS=3F7=jCr=QL?cVG8Zjb;%VSsvBh=CZ5CZ`Kxg(l`#s%7#(x jAG5x%XHhx28|?4Bz8(*i zKMlN){@0}FV!Qjxma+I6J&g>jzE`N{m%hoF=1con`SLf3*m?S#f^JtIG6tW9(SBq> za`7D!+Yv1)becxyqyf?#KY1 X^Eu7cy7KIr505>AU@L{h+?EwObMV3 zq%;|7pB@_UNJ?9MlHgpoxhU4N_6e&v0qSP4m)5mPeZkSNC*ApZ;ZR>;3PAF}K2bP0 zxOS@NqhH_SFjGA1@OxR2l^$xHZO`{*PS%@g&Cu7-j=WD MS7N_r-vpVtB-G*_)}WX(IKH-bbQeSg1NZ&i z;{q&TSSdaUwEf;_*adeU0x-P%^dh8}I0fhE!K3tBX3Mo>8rpDKCAD5}f-Ofo@zLgV z!(V_1Zn~!F#(euc@ry*W7Q;E&N$$3rB#G{^qd9u^)THsvgZp60Y@OtSOB#gHAh_#2 zrI1Kkvf-dnPpm=KN80$!93+nC{!hK-Vuu57*b$8lk VC8 zd6a+KL6l;U2WJqsIMz0sR%xh)RYa&IW6$f;Gti$H*nOWTIFC->cX1=OSyx8vZ9Dxf zdc%Z3SpeiL9nSvMVHA09^HRrN+4#Pa*qqOn#`o>JtSvW|c<8wV?bla`;O>i@txOMg zqT_wwIM$KBY<3v$y*`JGWvEx`b~?QHj`fI(`F%~&XuoQvJdQ4Evc}9Lpyfc-!d !8Igbcj1m*Hb$ tu z3(cV{a3DtO*S_>+uA{Hk+f%B00uwLOR`@yb196&7tz@g$P?`yd XCzloFe{*S@p>))@ zcyKI{=1kpC83JUpvbL|*&8`)+INM+?k4$H6{6u?yX}iDbm|FvbGiB^j^;J)Ap@4O$ z!^YidqHl7CJtHtbUq!l+JwqK_#}R>(Itr$^NU5zSZ$2^;RuTQ0CLAuSt=KvRSJ;th z%Y}Vc^?2O62~<0C&fD=~WL2PY4p^@0v|e91(<4aNRrOo&X1I*s^dPQaBNz8*yIo&S z#T_Q3;!~@4+9Yv~A?^ZN(fa+a+O|YMQKx;rjw*g>k`bkcu(nHxzbf>XFB)NC;~AR5 zeAyFStSt2h3Kkzy{so}5rt>Y=blvL$3Ca752k(=uo@0+Pw^&sXA0a>nlE)pnR Fccw;I+VN l4ObI&?0?r)Op z<+j|BMsjo^8^N)e)}GGC!MZso-rr{E__ekduA$H(T9}nmb0b2EWCRe6fvsFCx>b@F zK;oQER*IZhGO&`}RFc}6xW|)TB36O4Bt3t3tw!yJYWj`z)Hcg;?h6N{s*9Su*H{KJ z!lB7+|KwCjX pJh?{Hb7^dg*314QrYnc@@Lv~;7Y>Ts2wJgpKqUhfn N`z?H^qn8060pIMr$%Y7W{bU+q zjIIiCzPAtUq?8~5+Ol8eoQ%C+7&b}18C5rW M2s<2uP(=q}?sbF?Kiz3E(ypmPh1jfTrxL;b8{bcp{%?NlApUg_sc*B-t z2sVy2j6daYNWF_J3*|r^$rGF9rtOmgZct)U cP!!4pOl7KJioUSnb{si5a$rch89bcq z!&wKaDq2B B9LdEFKbj-iD5@SU}%e@VP)Z1siNNN7H0 zg|{x;DT?(IfqU(IaT^i-SP;=Ue#e4Co42%!UvrY!sP`f)BiWra_3=XDxzW(ig3IbE z =Iny;=>_b^Kp;(kkzY>#8J-LrXtgJot z?z^mj&_z00+=Udyv$(0p$BPZhI3PA~o+~@$em#?>uzD6sjd8eIB*X}4LYkf^H#O2C zHUc}&6mzh8=(^a|!OnxseH|+3kj~4jRXzOEJ{VadR(NaIW6VPV12MC?;xrFGkV(OF zfnSqg(=Beb8!OALWufWaao{ztfNeYJE${@b@#@<)mX%41c35s$S)zrV^VI3V37sjm z&cmE~QWcMVukKR7=wQe=vMc*cXCyNVb9Qs-b|%!r>UtyHVhJ`}|5ScrW+BGv<2o8Y zvRqWOJc7~U$m(;qn8oD;F9z|v`XSlpax$g76G_Pdc50HdQ*)T-R;KucCfsP)iM0tV z5=*uB+MZoh xX=qr8<9X7Y*CPMAib52sODj2=n?VkmjTA@4Zy0GD>?J=2DYvg zeU_e1HgORGfIx@5FichLz9Nf{_NFc{DX=+Gu-xu?2S@iiJ&t(f=I($vplPfGFkQ;T zQH2dg1{wkacHr;60AI%Ir;oqPiJQNV1^wFNQkzt6E^i5^p-=)*LqGLO#oixe9{(YD z+LPQA{ZK- 4MZGfo{QzAk9o&KnJ|r&6yBtYi%+X1K%Nc%LorRA!;nGXw(<0d@ z|H2>JP<&;{0!-*xUFs-MUXPeAj=Y0(J`n6cF{h>e*?eOG#E~K5W1yc6Dfq!ui(dQL z6bkc9L06&2)vR@)s6XWrw!+Y Qm%^x?^@-c6+<)M^fLPK(ih2Pgt(*r@~B}f{8Ux{^~ zq)EzBYPtLS1bN1Z wexf-LiVx`w`c7EXtepd>TBe &0PzTVqOXo~ zA746Yvc`p5b8J*#BQ@!ayn7nShgyZZ^p@ivZi&(6?+AJ5a@K)&T3Na_DGPG>fXHm! za&YwNo@OX^1?OpGs2)8xLTyb8C_fu0Y8&eCxYXkTgk+5jb2x_$Uvcrt$)+v+Q0by5 zn@-V;To+Xn^?m9c&>Q|FU7(g~f6XB7*tQeRQhDqpNYqbkY5PhE*z(O9SYdRo2H@FQ zxgT(1(~3HEd>WPZ=V^1mu&mDlc*%}WcThHtQIjNku>(xfFH>U`Hn%+dkw6lH(*sXm zl?66gXL=x(kIz0a@*WVkgaIuT&p)VMT0T)}U|rho4$bmNHWpAx^q!RNIvnq|sVDJq za|&8%syZz<3n{XvD;74o6&09$V`>vR%~R*TliRNrmUklUATEtvIpCLx?4K5nvt9*C z(RlI5c;kLf^!FXkf_&Jt>KVUL8z~dsjUz=6ZegRI*fi~6 O+=bl zqzAJpR#fSk9i(%9b(b)8(^L(1JZ_)8ls`h6V6Rm&hLh20QIb_7gC;}Wj-1k%&bIn# znH}17q|!T#$4{_;Q%UT8LV((|0E?3@l5VP;s!>R-a6Xovur0!gBO9XDr7o-Hp^O1; zV7 I^|aA21~h$3 zg9eAQb;F=IQjGpNSw;fd%vL(8!JSt;#oUY3W1X&w41o)PyV_jJ7~z9|2^3iyhDo10 z%?{zE(dP6M;-Gck8nV@{+@67-nsM0J-Fcc zKP|Is_~$e$qsd>!C+A1je|ujvl3V5!Z#5rJ-uV~>VKtO~xkhkB`8(n$qMe{8PuMF4 z&Wjqi^{d~VX}gX5=g%d6l(b?o7XNT VQ^l&AW>3MD^3bUi- MhpyejV1Le(+^YW>ux7?y|eL|tci8PPmNg9X!z4o|$nLO{H|u|(x*z3+E}{rf_L ZhDdhOZ`s3(a(%x7AtRwEUM*@6_&=3CFTDT& diff --git a/img/image13.png b/img/image13.png index 66a9a22fff04a293090f9d2fbe63d9bd0caf4972..023fbefc526398bfe57b25c32a6d248ff33ead6d 100644 GIT binary patch literal 7970 zcmXw;1yoeu_x6WIx}{_2K^o~27zOF>5QZ39Iz+lb8bpSa?p8V_hnA4;E{E %=|x?zQgTpYz;EHI;X`Sd>@*0037(UQPo5Kqh&<7Q#e+ZWlV_Pyhe|fP&l` zEia_Q%oV%o+0@RLSNOX;s |15Y*fdaStjMXQbB_yy>o9u1X+c o4;q(dJmanMwvOIp+p ~D*ZVEZ005hpk-qRdM=f >2nanyiyQOGgD zjgxKRX$MekfPnxoI1qv<-HRix8W)d7%}R2rvKFDF%As^VSg^wSUFFuYo4{eB#xX&k zqN$>{NhIBB*RAw*iKzfd()u>{Jf3j4z)L}wEz4RN_1GCen;Cl!GB_P6m5gQO45$?t zyR0Dp%k+s}##2)T3(vd@B!g+@o222z#*BsmRV2K(1Q^?(nl%baBZVUe=m9YUD9BM{ z{!K)5;?M1;etF`YbTs%)b2RkF=boF{>ppY94tU;MHOYvk5Ad7=5?~Vq1_RxS=q??g zgCs9@UEn%sa-D=-NILi=582-xLFPxjE<4P;pNHoZ$T~HK@h7?HSHhfi2?GIt+y{EY zweG3trkb7@&DpCcHW;iS2BPAlXQ_!hA(JoMJh9cDq;GdD*-7h{2y#)_mCJuExr^vH zjf1*O_ $191X+OK?!yEI;U*92cb zoYwg}H3sKPPJm>%S9ee8qkgN;Yi!y!ydB5vv~U0* 0atRShTwAYaSX0`Lm#D7ZdPq;~TX70--*PIyWNJ?X_%6GY~((sKrE1DqY}chb_( zzCI+uuZAyw=P=8LWD)GURGPlEby+v}5mmqvy#-N52`mP2FKNuU$tNh8k_b=gUA>vX z5Zvbx{~GYbf*3PLvCFNdv3k{Y=!$A>6jo;pZoe-*jZx6C@AJA1O?jD _fF&8A=`lIMz);8MrzUg&Whhns#B!SCU0>PfLF~Q55txnFC>y= zUpMU*BSkvIM}+}#f2 jThB;~mj3eO@pk!OLbw{fWH4j7N2<$b_tUtPH9lq+J2K(~X#c%Fey_uIDcbj+_NA zhTU$*em`J?Dyt>i8K!nNFB^tN>FT+pNT5H_UUNJMV`*y`TvLU$!f`mn%eN`=M$j?7 za=Ne&OCSZWA%*ti2fXqk%)z@;@C#dw3GUyq*G=H=0Et^9l2QpQlT|Q+!RnsnvfnC# z4kAWY?dJ`+6CH6wyiryQP~$%NkAng(38*-c@d8lfw8W1K#og$3@oP~{gcZ7S12#0B z0qOa80~)qngq*dr)Xkjjd(dUYQKl7@S%L+w{wcB`C;eUH6g R_JF>pYg z#4j8fVRjs~;?a>8B_lFO(3du^`8Y|Y!Qh>!s1WPjQ6f9NLV=_P@yaNUhm@ZAH#S!7 zV&%F!BUB9Rh*xO&IA&CQA^--MvPU$Cr#ikHKaMJCm9&c+lsHvL4rG;PZlOZ10T6aF z;+&J=Ntk{9iMGS&`mM&jsd(!xku(cVrKr9z=bVE1jlv!PmcbyiV!OHkr3wmdG^Rg5 z(c#doaZR^Zk9?b70cqwti@A3Z_dk?P??`?$m~ClX-+u33+QKx8$1F8X UU_CCSYI5vtt5n%L=NGccop za5?}x<0l&N86r>~8g)LJ9_<`p#cT8vr)>ipmIuZGRT(u%zROT+>?N-j{ru=JC|v9k zOAXOUIUw*38-6qSg`J8{{JyS~|79NjIJD?{H8TTt4Q52~7Yb^@>yi`(8BdbvRZrnA z_UCjnv7YhO96js?Jw9}oZFNS4fR0+0qBkv4U{g957=f=gkH!)ETl*X>NcLSCxD)9V zM+#?LEd1Dl@9HC{u<}axw#+CPUNEaePtbDU(xdJuzl2v hy_4l*N>prA$jf!U W~9L;pYJFyd?JilE2sf1+Rp y_xPPp$%tH1*P%1r>X7u{>R7J$#V|L(UR&x2kB4g&!dqX5~T6g(8r1dgBFaJO4 z*$vG8iD7 7v;#?O*<_5aZo8hBJn>y6P!XZHIje)KDH6QHLMGY(xMQjT}t`TQttoz6#1k3 zHKXxCKb^0{xnAGN5H@Dq)<~R2?~FT?O;By)A{g;N({zt#14zvp#s>+hoew1hJtk{Y z2tD>XrQkN;S#JAk%H2sEy}z9ol^O@41MCZ{UfkPbf9s2^m=VQ=I NVdqf a%?1&5g9}_apELCJ0Y{`|J@sw4AoT=BTdTn(rAzZauYdj zbCsCfmEvTlI%N$n>}(ylkz-H;H6X1uKiDZc=x4H5{Fmjp(_j3M&}tI5cDBWcWRO@( zVHlubO8vqAuhrFR_fack{QS`vuOq|oh4IIhfhi9Tw_a1@)7`|0F^E%|!P%`~LeZdq z_IaBoVwrX?p-?I{vZn)@H>c#8){0j?gn#tTqQ%MbVBgg6b%d_Fcddai?U$l(CIZDp z7pU$)b{S$sQ^Z>>b_> H|3kU4 zf~nZ=qzl5v)e$eGGGxL;CRFEgRQ}3EgGFj8Va)4o6TTWzcm!(fRXU2Wqxjsmi{|2G z`8@>?)yQvTFGH$y=po8CG9CMLj_oo=a~XKUdB$h$a%;n=d0~8W(EOf9H#=t@r&L z=YvY0#{mj)Z@zK;1nfrd_-EiMx$VnlF<_eN!E5~U{2ANhyzT)l^bl&DZMnjYSAM=a z#-}+S*<1Apz5C&F$%!{6pFk4jERybVpB`Eu??2t7w5qE*XBWI~ze+xK 0$_9mQ!0^c8f*}B|>z%hWX;(LGeLe|7&x1#>&$jA>H^|bRNL~7b|Ovvrk ?RoR OvZrb%to5sMWKuJ-i*{UKbi~Ds*T^8Dp&TU%-Q>Ef{ zl~BPLnsg%gqVL^ol+Nke{!L|!Y09tdC%<2RWSbe6@9erFNp1e95qkR*c{VNYCDKlo zYE>Cpy>Y6&``qVcNq-z)w?|`TZeI;nwUo#-$)N$Cd<^ssM+u;Ah_j6kFym*?sW5IF z+@#4Y@VnZ==D$I~V;7`V Vch=0yCkA`>G1{5fwTzJQB1CvgtU2eB_5?N&M*UQ+JjVT7ACG~u>$D5& zv@d||4wFbXg&RM+vPMr9&AVufQY9xzLE??%!zISU$kF$;0p@QT!SMlH# hfFqA^c~#!AX;{4MjDQKpZ8n!X3xnKoh7eOn@$2Qhqx7gP5q?rr z7Y_$9&EO!|8*_v2dt%R7K~URJOqNHUOG{#T_~qs r#!RS(@j_ulMD*Rc!~C|V^S )k@2a6_ zfkk~e3z`f*>>aR2!AtDI?nC<$u` WtE2B1UWPRk~q^R9c|y`Gga-O`pr1!0zIeB z$_GegqbD}Ya$MR~Z|r0vi}ym;DdMVH+Z*zQJD&VB|L9G0V@8H!o5>F%LuUhYsS#xd zP8=fk0X9C8S+a0xE;P Px!j~C}vrO#zAtBCLLyeqi*6TD@J-!A6j&!l! z%06e+ur_Y$U1=}DAL8#u3iXy#gpP$)%r+s8oIxMK%h@LnDz{b_;~s80 gzOQA4Qxxd!X{An9bp~m^Pp#rDIezCX4pL6rAI2Ff zWnT0i^EQCDt#vK88@U^*kIE2-CD+{6p|E!0V2mP<_~Jtma42l3?XqZm6qfg#M~V%^ z$}52`*)S#Jp%q>f#(r$11- W>bUJ_g#_|zGIzi&nfoM7D~6KzC`(4Sho+ye4|l}x#ixTM0^i` zU_8*?Jo2xRB !yn1>_g?7`N*Wz zdB=mV-fJ;h282baul>Hh+y7ue6p^X oICW*=akSY&@kJjtyY~SNE#RNAmRdBzen}-(Z|G=!1x4z7n+aCN#F5YNfC71Ev zg2ta1lwH9;eq#Qg^)-QFDL#%#YbZVhKFh-Z{goymdS0#;`HX$Vy|L=@|54xAFbc2N zee11Qqu?`Unkjnc2nq;jEohLXye F0 W!><*&1%-x}O^y?6_Axp2mv%|*i3 zYXc!l*_t8v*NZSVrQxQ}n7{`Y$8NQ4h))oVh;t#NMDoKmZYh{q3h9XLn+nN@$Pw^i z2Qptgr+3unIOY2&KND%@J9RRe7ik6&V78B@oE}+(f=oCx+oKg-ZKLZ$IUXUnM8SP2 zJI@u<0vKYDKTq{&->`(^ntJlH`r<`{pogv5->#)5riDK*W%FxJJy=S$j`oAzIa~!k zxVXoM`Yo&mFR#6zlC;IZ9|$h{j{h>FoI;dGyjruCc0-AmzrDkAt!sC6HKn8w%aWg^ zmfF;GsaDj4$TU!@pC!zft~gDC)ze13LNoozMactVFASuc-CBQ9GQGK;NPVXz3--@G zBo ~K z5;M%@IeUf(go-G78p%U~1>LNE?yODM9KN43vmrj%bEuPfcQ}m}*Hp4`v7ypDip z^yg_TmPSfa@M5!{h0)Hh4RLB>6*()JI@sky^C%)%uKfBvB+Rjp>IGG!QVMzvVPb9# zv;%snL|-9D^R|zL`HlY!-mxmi!s6U?xWpa4hvVlWzB|j7fo!Lp#rju#RlU|@;8aw% z$3|*Ob<};+wEP7$*a-xhP5p;kaYcQS1+`&pxIpo(ddJ}$*N@5)_~XN*1V>u6?B-;4 zzHj#2M!Z&Kn+;Q4;N%|f)n-3f->cBZ8CYC{Mpwaz6T>SuhV>J%i7+ hgvk$-qCC~Y6!WYHlm)}&E3vMbX=^bb zX1I+JaO1SpiWq$PvD27I9ixi-lHqC)icGSn;NO)0&zGmvb*XlqCx`m?e fw(}Qk&tgK3g7GUER&c!O0%%fOXas rsWzu=>A!t)5c$h`)453K*DR|N1Bu#7Td=$w!(Go#+YI(Y+*jeg z*MC) P!JQE_=HpCvjPxt6RllM UZQSy*M!5
`;r_FJI${iVrr z9pV*KkLW2Bw^o}_Wc=R&cK=KD5yNPs7#Gtwvz!ATP4%(UYdHMcIZnLwTYGK>Bdaz3 z+^;M#xY5>t^Tl$U7(Q%0we;inNv856rDm3cJfl*V(5_(3zlU)4W%z+yZ5V>m|8hr_ z{`D^9fiR6e4=bmH*Phr53;|1mBiL(|P*Elye4G;bWk>=gAhs|Xzj8Ok57;K*OuqN2 zgNOjJLv3Av)Z((6tBZx_?9fmpo1TWZha#K_FoLCQ8Fs%;sQkT<^bXC>z8ak-VGnu} zAao|Xo+)boM|3L3!!-468Z)le89t<`GB9@1mHb1*YNoWBuQOA|-*1O^ZeC?Gr*h+o zi$yxFPh>fbzSfmqoHEf|m9a~(Ooxy>GMG2B=-s!%##+=!5(o)9+Kj#XKtWDuCI$G- zsG28}5C60*%)t#t`Yqu_4Owe#ZJLS^2sfr>!Oh|+koU Z z?lRxebd{EtCXH2hVOonH^Lxl3rB`$cDl)}$Ka$&j!iP_s2HU9&e$!jo>LlXEZidC_ z>dZ{Jwv5nfzPrZxVfx(;{>6x&a=&iKv#tVRIvOQXClmaf+XY_NMMa6=-We#=Wa@(% zM$tKEY0~#Og=hI{)Uy%>?|!9srf3gUf%MDaw=a}uF9O$)PB7Y9#+;=m3Y@I0eqOER zQ{ia#|B23U_h8W{^{!6;t)0UB)3b}~ 7x`x57VbEVbTKviFT7Dd8`8a5#pTh8vmUxXBPi%D zF$L*42wK@%Mf?43eCygtBzy5bZL!heV#Cq{qrgBr1-`)Ova6BzcT(O5D8d8-=MbsS z@!WLY^i*{t1%_iq@Km9|if NxUnV z5NJ9T-k(8bAd!;3W}D)^&)?GrkA~R%xdp=->l4gtD8d!YceLVd_93LCu9TMzNkFl> zs9k)MH!&$D3&su?MN$ba)7T;vk@Y=-OIE>99Trcu=q6Kr?;!Z1XQsK!f;hADw{4sC z*Dt1*I~C_Q%T*~V1S*F5_i~P@byyTjt6~y?#avz_(1>&8ztUQi|C~p#1dqGrcr=>f z?}3Jqs4fc!I`EhOd`m2ePCwhwNkK&|9NLVnn_{7V6v}!WnC)@)>}Eo*oa~MN X-3jhCxZB{a!3pl}5Zv7*Sb!jp{P*2=@2geS zJ=Jxl=j`2eruVn@iBMLQLO~=%gn)oRk&zZxg@AyXdH>7{5A}Y0Y);^YfIx?k5f@Sa z26>jHZ%v|=a)kE+$%gEKA6%f#NVIl )i!~J7Gst-iL)`L_hOmZ=gVR@; zys#jKRUD1RPM{wRk+lIVENYBI0E-DX$K?|;H_e6@CRa@`bUut>md!M$Z*b6jU%pbJ zIA8620-lYJNoHJFHlJUy{_gi@vm8i$OpEDf1oPi|A`6h8{1qx4j2{pX-8~Ajp+L6L z&NpO*VujNA2ql#A!j E!h1#kQEA=EWl!G0VF)m)1>Jq zY5$+GuwS595AlCyN4O2Z_rEJiDz`18E5dsT7&%NrIUNgsD|Bd(>-Er8hLmjtZ<2}W z=AjTQ7cP>E$f^GUHDnCVPSp`1=~EyoJ2GkRwA) dvW>W#A5deOf0p&^vgxb#lsDMG}T2QEuif9 zJDbAO1nBZX2{g*xB6a@6N6K4yDVW5vt`ZI9@JFKGaC4_Q {3505r+LpSHPp)#Pxw#YcrEe!@HOn(vN7td3Sne&sI8n|$C!e6 zA~QsaT1}tCO$eW38+w__dJ7=|A6Q^3>Qs8Q=^!*V6qz8)$qAu0aLDP0Vu>M)(Ab(I zpM|~_U%g4>I)n&AP|;#hKwz+k^9%G+Z}H^$FNRRo{U~K=R-1gIA#i1*agMRjkP4GX zF+BlcYH6Cp=c#E~&vx3-(acxrKcGJNH)wKxFCQ~8E+E)|C@}bx3nkG4nW9Ov*(_lJ zMbwcPH`?_o5`0mdjY-_!jr|d(W}^_7)ap}@NUJK0AC52{p}u3K88mjalQ dBiz7|Ny;zJTOpK*C@b0BJDV8DB+h>99Ell!2%@0Np7~JH& z^l=>{H7g)$%<27fg%9H0SUr%OB-k${C3f^iZbmJ!mcz{an5YfsIjr_Dj=}(N%vI^#BNtg?P^^HqUS6|9`q-L z@tti)9^Q?@Dx~`~qWg1+9%vKj+4vk0)j_eT*$-32^9~ei)s>XFED)7lQP~X3LFpK` zsQhQC@Z+o|%x@d(63S)~#qb^eC4E73vP#FY@%HniB9suZ%Meh)kivE1Osq8KnBuzu zWLtGK}QC?h d>1+%a?$r}GgdHUE#8X6*9 z2m@yc{R6st`Epq38+rHj<^Fvde>!2qN%%BY?+-9RVp(XrFOvY0484_4GKvH-*RU*? z?2v!b$T$c}itrdp8lznKGr;g03*=ksun=h9xJaS7tro^Pg_3*M3A|1}I;zjiZ=Mh_ zL7>!CV+j3I73yqf3n#CVk9&yP0$i*dn8{%V)2yR88=(!g&Qx_Po `V9ccCs^q z^1$<1j*K1 )+pTtw0I2aVf?=beY;fa~xsF*&3)$c4oM|2hVzqd2Ho#mV+e zJ8-k 5q zC?m7dGydTd^tEe~7^-C*@`I70>5z7OJ%a?`@iYWaLDXsTo33#mY-v8s5&RXe!N&m~ zGYabbC{bC+>>zRs-xM`Xo>Q7l7|Y>)vx4bej nmn T- zZ#D{B62%rOgpZGar~wkOqhEuIqUCCbf^l8iE9>028nzG2%>p%mpHfRuw|Ne=odNaz z(JI%^#+FP|6@_#e(v6PS_KIP~QLdOe_ydxeM=*!k@kx~>B_No3#vojml+sP%C%M1X z{nrylA+*;JNGhc}jUg=rV2Mh}!YNk2{q{}{(uW=c7%4<`!%7*5ImPU7n6W`T$kN!s zb3>rUb+N0wC_)M#$s04t+-w)Zgh5TJ!@$MK90$l*q43Yd30#;gT`4d}s$A2Up5Ml# z>1UTP1TQ6!J `MOgb-?9%MxpcfxiI@XUJ%#$b1X9`^(h1Uty$=T3unePr8$p=KGkzObQ;uH@%; z=Cf_{v^Mu6kIf%2MGtZPY81NB=7P7wZR^YTT ~J`ra2@EHGMikgy-s~Vol0!?ijC>>XZ?R zE3h9vzd8OsW|m!b^-aQ0%S}U&Kk2#p>?bh&M#=CbU6m7iRr(zNJ=iyu;8p#dx4b_- z>ztV=bHM~KwA9}g_+xnS4Irdb^gfi}u%YlOGVS%D`Kx1WK*s_^#TxvB8X$KAP=*Po z5Y#d?ZOa4Kd!7dA!w_Y!I42@Cka5BnT416*q(BHo@Rb4b&JEqVmC;G~0TbcEZ_Y7i z0p-8Zjc{|>1^7dV$eBK-Kt8sa!-k>we%%kB78pP;W&m%g6Zng9cw@ WbcC zJJe%QA!X+wCL~92> xR4{7DApr?YmL|crf6wSEB)L z7mY~j5(IT11GxE_Qu+52qE-!LGw<)C@donXG5k7&9q8TzOhXAT3F-zUAqc>;2r&ej zK;Iw`d&cC@AHi-de`N}CnSzFB= z66dHF86DbzZVSNa5EZ74Ra3Y`g02EWlyy)yfZ&D~mwo>w_*4KzDtaCSi?R~}M!&d9 zpcteBBryw&?0b=<5dAkV3a;OoM+>I$1OB56N_6L#3u9cJzh%z9 9!QZN5NB?}%>@3P4w)E??+ _EvyCSe^huevs-)Ul7oA8fUt6qlA#Is<6&S2=cXXWuhqwXO3o=0ETxd?P5eK5x$nU3?(5h4u z2rc)K2W5svG%Y=qu2k9YrD%#SxXbw+u5JyMm2)*Ux((ak)duX2e)sS?foyfWnKj*I zj&rg^#CQ*h$NW<8^y2&4zGiGb*XzEBWLxBolyoJw?Pj1q8|rSnWyy(?j%tlLJqKy# z2Xo7XR}u2+cRXc#`{c8)Qg+WM99gwu9sM}LY^zON^FCY^9eoIE-anDDL~WJJe$tad zdfZW~>Z=6d^!$?PD~YL~aPfK3bIyegziWV_6;<|{{#|z qv-9uy}+gcf7wJ7Ej -1R zFTI#nfF|AGZ`N}cKU0(`a*w?b#N78fmkBruoF{*sAb8wa62zyFHHGzc+2lFM{@N$u z@fD8PTMWA#W(x}wV|&RyBXH`srEp*CI`^i7oFrFS)p&Wx92*(0Pp0{me_=%v*;l%J zd;6h399l~g4X7|@E!j!SmxG^BBA)F64Sl1(#5C5tH+Fsvg$ERM@Xm-LBSkd$!JG&2 zidh(Q-z_ej58VKPYWu0Kv)OWEmc~n@8_lJ~RpWB!1Pn-I`=$|VMQ=5?wtmft))5F6 zF&d1dA>2d8%(N9 ); z8QVZcg;7=!TS<6L+fC5f2nAxK9cSa8F9cj@rz%eh!Q52Gogh2GBzw1rf%}M({Scs2 zP8HnxM~iyh;3X_Volwb*We@f|g#LcTal5;9?{@m@SDCxWG^(n0sn?&IBkHihw_9FT zQ9j1A5X+XFIHQw1Qh5=W7n||%E`8J1f-d|;NNXh*pX94|{j{+>RPMX6-Xk!qM)p#K z=W1**XOaw_G`p|k>*n$xo^8JgX!p~-Y)YIlz<~z1!2=aCt)(_jFD(u^ejnwu$UN`~ zyv+7&5yrl$c0S9uu1N#Ou6HtH_nNyBQ`2wkL4KGRR0}htY4DSU`T4n*rW09FDLY>V zPXOz_b}8RW7*Xo*=G%VIn`?R^>CL~do)r$Vgse8U3bi aaKyTv$!Hgoj~Sa6s_4;JCr&82 z_@Sdq*y0j*$wa<>xBP%o=Uzo0b|$-qGCSv_y~ohp_DeZAX~!c~9M^}7%uw)r^1*Ro zftP>O-BDq4zVnvdz^&M9zsqZshZK==WV5g-oC;(6o42$iT|Exkelyv~u^55sdvxO* zCxkw9IeLl9kxp-aQi`>E&kwTokJjDf1|am*k%0
SN) zO-iI+eeq{({ef@g8{ZQM@Wuy)vPXrNEki>_^_*hJUMV)i!GdRY+A{W+!}i}1tkV^ JLWf`_2F9Hd(v0UpsAfj6w9f1z s4tsg=TEsJdM4UvPxW<{c&~B`vi>9aL<%{=MdR$ zh2>K=`+C=#>^Iu-nNmmd^R-4Uh2jo#;=Zqmm^n%BGTun1g6LaEJdKWf`SKwVHqpF@ z=qWFAl2fNn%-s1qNLIvnA40a)we-XN+H%V;lkW(PB{mI7h52gBk?Hq{(K68n&L0~N z@&sAEbxcy*orRra@Z3hE>?Y=$tp-RWBfOuA+n>`(3zgc8=^Bltq5h^POsH?KZ}XJ7 z%{XBb=v3+XvrA5oFE qaV_!A0p_c^O;Ybe zQrPv(GDn^x=(dwqnggLDWjg|09s62fjo)HiY{IxQ6w+QA&oq Us{KH?iqk9Ry+%h@!Sn-AlXt6jVwg*2=>-j}x2KBUt2AmCqgVT+uDvKT z6CS!;cXrg3^y#h9=yv7P$=9(}p3+wls-r)t)ne)OEYh2;-?q-=3viw zVV=o_mnLmQm0E8aZcL}!Lt|s2*bTeuAZGVHj@WrL>*Nj>tSxK=%pgfI6IZ@*z?h7W z!FT2gQ0GkF^2#yuZ5mRrxzpfH-5kUBVKx2XF?-Oxz&RXQD*{l#z7^!Hr}c%;l?8c( zZ)jhR2m$Oxl4?enfwwZ?YT%uJWZUAUIkd{I7|%2+Vua^OUk{5TQhE4CD~HD&^)z~M zvbjwVi~f8k%;|TGiGBzDekHL#%dRH_ePew_zV8=i?(Ycwk;zZiPtZKi9ZVJ_T}q2n zfgF?u&q!lN46E$N8JfkzDLr$v8rQ9#lSL%Rax@;#uv<^bnC}*&SjS#6yl*mCl)66d z8#xa1b5&j(DAYyQUsGcWS^zZ=gFe>iYRiwwjT>CnWFb}ma`ZuB`QxUTemQ54B$Ysz zm^gAuGr)B4+FpE_X2QblmLXtjdI&atDqpHiPHy!!4-sIT*pzTlQcXVZa2ZEA_EMFV z387k*kH< +T& z+75>IcgckN$g@d?dFiJUzTu2Nlzk1IH_fSAhsBMKHxvY4B|q&ptelum7PxAuo0&^U z_*m(MPig57AD?;I!~}>~LpPct&}SqKqWh+lX}z4`V>%FB`97l1JFOJ9AftYQw3N}| z0=EL`gFtm`FIS=3F7=jCr=QL?cVG8Zjb;%VSsvBh=CZ5CZ`Kxg(l`#s%7#(x jAG5x%XHhx28|?4Bz8(*i zKMlN){@0}FV!Qjxma+I6J&g>jzE`N{m%hoF=1con`SLf3*m?S#f^JtIG6tW9(SBq> za`7D!+Yv1)becxyqyf?#KY1 X^Eu7cy7KIr505>AU@L{h+?EwObMV3 zq%;|7pB@_UNJ?9MlHgpoxhU4N_6e&v0qSP4m)5mPeZkSNC*ApZ;ZR>;3PAF}K2bP0 zxOS@NqhH_SFjGA1@OxR2l^$xHZO`{*PS%@g&Cu7-j=WD MS7N_r-vpVtB-G*_)}WX(IKH-bbQeSg1NZ&i z;{q&TSSdaUwEf;_*adeU0x-P%^dh8}I0fhE!K3tBX3Mo>8rpDKCAD5}f-Ofo@zLgV z!(V_1Zn~!F#(euc@ry*W7Q;E&N$$3rB#G{^qd9u^)THsvgZp60Y@OtSOB#gHAh_#2 zrI1Kkvf-dnPpm=KN80$!93+nC{!hK-Vuu57*b$8lk VC8 zd6a+KL6l;U2WJqsIMz0sR%xh)RYa&IW6$f;Gti$H*nOWTIFC->cX1=OSyx8vZ9Dxf zdc%Z3SpeiL9nSvMVHA09^HRrN+4#Pa*qqOn#`o>JtSvW|c<8wV?bla`;O>i@txOMg zqT_wwIM$KBY<3v$y*`JGWvEx`b~?QHj`fI(`F%~&XuoQvJdQ4Evc}9Lpyfc-!d !8Igbcj1m*Hb$ tu z3(cV{a3DtO*S_>+uA{Hk+f%B00uwLOR`@yb196&7tz@g$P?`yd XCzloFe{*S@p>))@ zcyKI{=1kpC83JUpvbL|*&8`)+INM+?k4$H6{6u?yX}iDbm|FvbGiB^j^;J)Ap@4O$ z!^YidqHl7CJtHtbUq!l+JwqK_#}R>(Itr$^NU5zSZ$2^;RuTQ0CLAuSt=KvRSJ;th z%Y}Vc^?2O62~<0C&fD=~WL2PY4p^@0v|e91(<4aNRrOo&X1I*s^dPQaBNz8*yIo&S z#T_Q3;!~@4+9Yv~A?^ZN(fa+a+O|YMQKx;rjw*g>k`bkcu(nHxzbf>XFB)NC;~AR5 zeAyFStSt2h3Kkzy{so}5rt>Y=blvL$3Ca752k(=uo@0+Pw^&sXA0a>nlE)pnR Fccw;I+VN l4ObI&?0?r)Op z<+j|BMsjo^8^N)e)}GGC!MZso-rr{E__ekduA$H(T9}nmb0b2EWCRe6fvsFCx>b@F zK;oQER*IZhGO&`}RFc}6xW|)TB36O4Bt3t3tw!yJYWj`z)Hcg;?h6N{s*9Su*H{KJ z!lB7+|KwCjX pJh?{Hb7^dg*314QrYnc@@Lv~;7Y>Ts2wJgpKqUhfn N`z?H^qn8060pIMr$%Y7W{bU+q zjIIiCzPAtUq?8~5+Ol8eoQ%C+7&b}18C5rW M2s<2uP(=q}?sbF?Kiz3E(ypmPh1jfTrxL;b8{bcp{%?NlApUg_sc*B-t z2sVy2j6daYNWF_J3*|r^$rGF9rtOmgZct)U cP!!4pOl7KJioUSnb{si5a$rch89bcq z!&wKaDq2B B9LdEFKbj-iD5@SU}%e@VP)Z1siNNN7H0 zg|{x;DT?(IfqU(IaT^i-SP;=Ue#e4Co42%!UvrY!sP`f)BiWra_3=XDxzW(ig3IbE z =Iny;=>_b^Kp;(kkzY>#8J-LrXtgJot z?z^mj&_z00+=Udyv$(0p$BPZhI3PA~o+~@$em#?>uzD6sjd8eIB*X}4LYkf^H#O2C zHUc}&6mzh8=(^a|!OnxseH|+3kj~4jRXzOEJ{VadR(NaIW6VPV12MC?;xrFGkV(OF zfnSqg(=Beb8!OALWufWaao{ztfNeYJE${@b@#@<)mX%41c35s$S)zrV^VI3V37sjm z&cmE~QWcMVukKR7=wQe=vMc*cXCyNVb9Qs-b|%!r>UtyHVhJ`}|5ScrW+BGv<2o8Y zvRqWOJc7~U$m(;qn8oD;F9z|v`XSlpax$g76G_Pdc50HdQ*)T-R;KucCfsP)iM0tV z5=*uB+MZoh xX=qr8<9X7Y*CPMAib52sODj2=n?VkmjTA@4Zy0GD>?J=2DYvg zeU_e1HgORGfIx@5FichLz9Nf{_NFc{DX=+Gu-xu?2S@iiJ&t(f=I($vplPfGFkQ;T zQH2dg1{wkacHr;60AI%Ir;oqPiJQNV1^wFNQkzt6E^i5^p-=)*LqGLO#oixe9{(YD z+LPQA{ZK- 4MZGfo{QzAk9o&KnJ|r&6yBtYi%+X1K%Nc%LorRA!;nGXw(<0d@ z|H2>JP<&;{0!-*xUFs-MUXPeAj=Y0(J`n6cF{h>e*?eOG#E~K5W1yc6Dfq!ui(dQL z6bkc9L06&2)vR@)s6XWrw!+Y Qm%^x?^@-c6+<)M^fLPK(ih2Pgt(*r@~B}f{8Ux{^~ zq)EzBYPtLS1bN1Z wexf-LiVx`w`c7EXtepd>TBe &0PzTVqOXo~ zA746Yvc`p5b8J*#BQ@!ayn7nShgyZZ^p@ivZi&(6?+AJ5a@K)&T3Na_DGPG>fXHm! za&YwNo@OX^1?OpGs2)8xLTyb8C_fu0Y8&eCxYXkTgk+5jb2x_$Uvcrt$)+v+Q0by5 zn@-V;To+Xn^?m9c&>Q|FU7(g~f6XB7*tQeRQhDqpNYqbkY5PhE*z(O9SYdRo2H@FQ zxgT(1(~3HEd>WPZ=V^1mu&mDlc*%}WcThHtQIjNku>(xfFH>U`Hn%+dkw6lH(*sXm zl?66gXL=x(kIz0a@*WVkgaIuT&p)VMT0T)}U|rho4$bmNHWpAx^q!RNIvnq|sVDJq za|&8%syZz<3n{XvD;74o6&09$V`>vR%~R*TliRNrmUklUATEtvIpCLx?4K5nvt9*C z(RlI5c;kLf^!FXkf_&Jt>KVUL8z~dsjUz=6ZegRI*fi~6 O+=bl zqzAJpR#fSk9i(%9b(b)8(^L(1JZ_)8ls`h6V6Rm&hLh20QIb_7gC;}Wj-1k%&bIn# znH}17q|!T#$4{_;Q%UT8LV((|0E?3@l5VP;s!>R-a6Xovur0!gBO9XDr7o-Hp^O1; zV7 I^|aA21~h$3 zg9eAQb;F=IQjGpNSw;fd%vL(8!JSt;#oUY3W1X&w41o)PyV_jJ7~z9|2^3iyhDo10 z%?{zE(dP6M;-Gck8nV@{+@67-nsM0J-Fcc zKP|Is_~$e$qsd>!C+A1je|ujvl3V5!Z#5rJ-uV~>VKtO~xkhkB`8(n$qMe{8PuMF4 z&Wjqi^{d~VX}gX5=g%d6l(b?o7XNT VQ^l&AW>3MD^3bUi- MhpyejV1Le(+^YW>ux7?y|eL|tci8PPmNg9X!z4o|$nLO{H|u|(x*z3+E}{rf_L ZhDdhOZ`s3(a(%x7AtRwEUM*@6_&=3CFTDT& diff --git a/kvs_array_bin.c b/kvs_array_bin.c index 2fa0d27..af7f563 100644 --- a/kvs_array_bin.c +++ b/kvs_array_bin.c @@ -235,13 +235,22 @@ int kvs_array_save(iouring_ctx_t *uring, kvs_array_t *inst, const char* filename for (int i = 0; i < count; i++) total += lens[i]; task_t *t = submit_write(uring, fd, bufs, lens, count, current_off); + cleanup_finished_iouring_tasks(); - if (!t) { close(fd); return -4; } + if (!t) { + perror("task init failed"); + goto clean; + } current_off += (off_t) total; } +clean: + while (!uring_task_complete(uring)) { + usleep(1000); + cleanup_finished_iouring_tasks(); + } close(fd); return 0; } diff --git a/kvs_hash_bin.c b/kvs_hash_bin.c index 6283c21..b529d61 100755 --- a/kvs_hash_bin.c +++ b/kvs_hash_bin.c @@ -273,7 +273,9 @@ int kvs_hash_save(iouring_ctx_t *uring, kvs_hash_t *inst, const char* filename){ for(int i = 0;i < inst->max_slots; ++ i){ for (hashnode_t *n = inst->nodes[i]; n != NULL; n = n->next) { if (!n->key || n->key_len == 0) continue; - if (n->value_len > 0 && !n->value) { close(fd); return -3; } + if (n->value_len > 0 && !n->value) { + goto clean; + } uint32_t klen = htonl((uint32_t)n->key_len); @@ -308,14 +310,21 @@ int kvs_hash_save(iouring_ctx_t *uring, kvs_hash_t *inst, const char* filename){ task_t *t = submit_write(uring, fd, bufs, lens, count, current_off); - - if (!t) { close(fd); return -4; } - + if(!t) { + perror("task init failed"); + goto clean; + } + cleanup_finished_iouring_tasks(); current_off += (off_t) total; } } +clean: + while (!uring_task_complete(uring)) { + usleep(1000); + cleanup_finished_iouring_tasks(); + } close(fd); return 0; } diff --git a/kvs_rbtree_bin.c b/kvs_rbtree_bin.c index 64c88b0..27cf03d 100644 --- a/kvs_rbtree_bin.c +++ b/kvs_rbtree_bin.c @@ -469,7 +469,7 @@ static int kvs_rbtree_save_node(iouring_ctx_t *uring, int fd, off_t *current_off if (node == inst->nil) return 0; int rc = 0; - + rc = kvs_rbtree_save_node(uring, fd, current_off, inst, node->left); if (rc < 0) return rc; @@ -504,9 +504,12 @@ static int kvs_rbtree_save_node(iouring_ctx_t *uring, int fd, off_t *current_off for (int i = 0; i < count; i++) total += lens[i]; task_t *t = submit_write(uring, fd, bufs, lens, count, *current_off); - + cleanup_finished_iouring_tasks(); - if (!t) { return -4; } + if(!t) { + perror("task init failed"); + return -4; + } *current_off += (off_t) total; @@ -527,7 +530,11 @@ int kvs_rbtree_save(iouring_ctx_t *uring, kvs_rbtree_t *inst, const char* filena int rc = kvs_rbtree_save_node(uring, fd, ¤t_off, inst, inst->root); - close(fd); + while (!uring_task_complete(uring)) { + usleep(1000); + cleanup_finished_iouring_tasks(); + } + close(fd); return rc; } diff --git a/kvstore.c b/kvstore.c index ba26a19..c12c38b 100644 --- a/kvstore.c +++ b/kvstore.c @@ -8,6 +8,7 @@ #include "memory/alloc_dispatch.h" #include "common/config.h" #include "diskuring/diskuring.h" +#include "replica_shm.h" #include #include @@ -29,10 +30,21 @@ unsigned long long global_seq; extern int global_oplog_fd; +replica_shm_t g_rep_shm; + +__attribute__((noinline)) void __completed_cmd(const uint8_t *cmd, size_t len, unsigned long long seq){ + asm volatile("" ::: "memory"); } +// __attribute__((noinline)) +// void __replica_notify(uint64_t seq, uint32_t off, uint32_t len) +// { +// // 空函数即可,目的是让 uprobe 拿到参数 +// asm volatile("" ::: "memory"); +// } + int kvs_protocol(struct conn* conn){ if (!conn) return -1; char *request = conn->rbuffer; @@ -68,10 +80,6 @@ int kvs_protocol(struct conn* conn){ int dr = resp_dispatch(&cmd, &val); - __completed_cmd(p, len, global_seq); - global_seq ++; - - /* * 语义建议: * - resp_dispatch() 即使返回 -1(比如 unknown command / wrong argc), @@ -88,29 +96,45 @@ int kvs_protocol(struct conn* conn){ } } else { // persist into oplog - if(global_cfg.persistence == PERSIST_INCREMENTAL){ - - /* 执行成功:在这里保存到日志中(只记录更新类命令) */ - if (cmd.argc > 0 && cmd.argv[0].ptr) { - /* 更新类命令:SET/DEL/MOD/RSET/RDEL/RMOD/HSET/HDEL/HMOD/SAVE */ - const resp_slice_t *c0 = &cmd.argv[0]; - int is_update = 0; - if (c0->ptr && c0->len) { - if (ascii_casecmp(c0->ptr, c0->len, "SET") == 0 || - ascii_casecmp(c0->ptr, c0->len, "DEL") == 0 || - ascii_casecmp(c0->ptr, c0->len, "MOD") == 0 || - ascii_casecmp(c0->ptr, c0->len, "RSET") == 0 || - ascii_casecmp(c0->ptr, c0->len, "RDEL") == 0 || - ascii_casecmp(c0->ptr, c0->len, "RMOD") == 0 || - ascii_casecmp(c0->ptr, c0->len, "HSET") == 0 || - ascii_casecmp(c0->ptr, c0->len, "HDEL") == 0 || - ascii_casecmp(c0->ptr, c0->len, "HMOD") == 0) { - is_update = 1; - } + /* 执行成功:在这里保存到日志中(只记录更新类命令) */ + if (cmd.argc > 0 && cmd.argv[0].ptr) { + /* 更新类命令:SET/DEL/MOD/RSET/RDEL/RMOD/HSET/HDEL/HMOD/SAVE */ + const resp_slice_t *c0 = &cmd.argv[0]; + int is_update = 0; + if (c0->ptr && c0->len) { + if (ascii_casecmp(c0->ptr, c0->len, "SET") == 0 || + ascii_casecmp(c0->ptr, c0->len, "DEL") == 0 || + ascii_casecmp(c0->ptr, c0->len, "MOD") == 0 || + ascii_casecmp(c0->ptr, c0->len, "RSET") == 0 || + ascii_casecmp(c0->ptr, c0->len, "RDEL") == 0 || + ascii_casecmp(c0->ptr, c0->len, "RMOD") == 0 || + ascii_casecmp(c0->ptr, c0->len, "HSET") == 0 || + ascii_casecmp(c0->ptr, c0->len, "HDEL") == 0 || + ascii_casecmp(c0->ptr, c0->len, "HMOD") == 0) { + is_update = 1; } + } - if (is_update) { + if (is_update) { + if(global_cfg.persistence == PERSIST_INCREMENTAL){ kvs_oplog_append(p, len, global_oplog_fd); + } + + // __completed_cmd(p, len, global_seq); + // global_seq ++; + + if (global_cfg.replica_mode == REPLICA_ENABLE) { + uint32_t off = 0; + int ar = replica_shm_append(&g_rep_shm, global_seq, p, (uint32_t)len, &off); + if (ar == 0) { + // __replica_notify(global_seq, off, (uint32_t)len); + global_seq++; + + } else { + // shm 满或异常:你可以选择降级(比如直接跳过复制,或阻塞/丢弃) + // 为了不影响主路径,这里先打印并跳过 + fprintf(stderr, "replica_shm_append failed %d\n", ar); + } } } } @@ -245,7 +269,8 @@ int init_config(AppConfig *cfg){ printf("=============== Config ===============\n"); printf("IP : %s\n", cfg->ip); printf("Port : %d\n", cfg->port); - + + printf("Replica-Mode : %s\n", replica_to_string(cfg->replica_mode)); printf("Mode : %s\n", server_mode_to_string(cfg->mode)); printf("|—— Master IP : %s\n", cfg->master_ip); printf("|—— Master Port : %d\n", cfg->master_port); @@ -268,7 +293,24 @@ int init_config(AppConfig *cfg){ } void init_disk_uring(iouring_ctx_t *uring_ctx){ - iouring_init(uring_ctx, 2048); + // iouring_init(uring_ctx, 4096); + iouring_init(uring_ctx, (1024*8)); +} + +void dest_disk_uring(iouring_ctx_t *uring_ctx){ + iouring_shutdown(uring_ctx); +} + +int kvs_replica_init(void) +{ + if (global_cfg.replica_mode == REPLICA_ENABLE) { + int rc = replica_shm_open(&g_rep_shm, REPLICA_SHM_NAME, REPLICA_SHM_SIZE, /*create=*/ 1); + if (rc != 0) { + fprintf(stderr, "replica_shm_open failed rc=%d\n", rc); + return rc; + } + } + return 0; } @@ -279,6 +321,7 @@ int main(int argc, char *argv[]) { } global_seq = 0; + kvs_replica_init(); init_memory_pool(&global_cfg); init_data_file(&global_cfg); init_disk_uring(&global_uring_ctx); diff --git a/kvstore.h b/kvstore.h index b0f386c..2184b53 100644 --- a/kvstore.h +++ b/kvstore.h @@ -279,7 +279,6 @@ extern kvs_rbtree_t global_rbtree; extern kvs_hash_t global_hash; #endif -void __completed_cmd(const uint8_t *cmd, size_t len, unsigned long long seq); #endif diff --git a/reactor.c b/reactor.c index c38289c..f04090a 100644 --- a/reactor.c +++ b/reactor.c @@ -336,7 +336,9 @@ void sync_wakeup() { ssize_t n = write(wakeup_fd, &one, sizeof(one)); } - +// #include "diskuring/diskuring.h" +// extern iouring_ctx_t global_uring_ctx; +// extern void iouring_tick(iouring_ctx_t *ctx); // 定时器 int handle_timer_fd_cb(int fd){ @@ -349,14 +351,15 @@ int handle_timer_fd_cb(int fd){ if (n < 0 && errno == EAGAIN) break; break; } + // iouring_tick(&global_uring_ctx); } int init_timer_fd(void){ int tfd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC); struct itimerspec its = { - .it_interval = {1, 0}, // 每 1 秒 - .it_value = {1, 0}, // 1 秒后首次触发 + .it_interval = {0, 100 * 1000 * 1000}, // 100ms = 100,000,000 纳秒 + .it_value = {0, 100 * 1000 * 1000}, // 首次 100ms 后触发 }; timerfd_settime(tfd, 0, &its, NULL); @@ -406,12 +409,12 @@ int reactor_start(unsigned short port, msg_handler handler) { return -1; } - // timer_fd = init_timer_fd(); - // if(timer_fd < 0){ - // close(epfd); - // close(wakeup_fd); - // return -1; - // } + timer_fd = init_timer_fd(); + if(timer_fd < 0){ + close(epfd); + close(wakeup_fd); + return -1; + } int i = 0; diff --git a/replica_shm.c b/replica_shm.c new file mode 100644 index 0000000..5a35e6e --- /dev/null +++ b/replica_shm.c @@ -0,0 +1,110 @@ +#include "replica_shm.h" +#include +#include +#include +#include +#include +#include +#include + +#define REPLICA_SHM_MAGIC 0x52504C43u /* 'RPLC' */ +#define REPLICA_SHM_VER 1 + +static inline uint64_t align8_u64(uint64_t x) { return (x + 7u) & ~7ull; } + +int replica_shm_open(replica_shm_t *s, const char *name, size_t total_size, int create) +{ + if (!s || !name || total_size < (sizeof(replica_shm_hdr_t) + 4096)) return -EINVAL; + memset(s, 0, sizeof(*s)); + + int flags = O_RDWR; + if (create) flags |= O_CREAT; + + int fd = shm_open(name, flags, 0666); + if (fd < 0) return -errno; + + if (create) { + if (ftruncate(fd, (off_t)total_size) != 0) { + int e = -errno; close(fd); return e; + } + } + + void *p = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) { + int e = -errno; close(fd); return e; + } + + s->fd = fd; + s->map_size = total_size; + s->hdr = (replica_shm_hdr_t *)p; + s->data = (uint8_t *)p + sizeof(replica_shm_hdr_t); + + // 初始化头 + if (create || s->hdr->magic != REPLICA_SHM_MAGIC) { + memset(s->hdr, 0, sizeof(*s->hdr)); + s->hdr->magic = REPLICA_SHM_MAGIC; + s->hdr->version = REPLICA_SHM_VER; + s->hdr->capacity = total_size - sizeof(replica_shm_hdr_t) - sizeof(replica_rec_hdr_t); + s->hdr->write_off = 0; + s->hdr->last_seq = 0; + } + + printf("capcity:%ld\n", s->hdr->capacity); + + return 0; +} + +int replica_shm_append(replica_shm_t *s, uint64_t seq, const void *buf, uint32_t len, uint32_t *out_off) +{ + if (!s || !s->hdr || !s->data || !buf || len == 0 || !out_off) return -EINVAL; + + uint64_t cap = s->hdr->capacity; + uint64_t off = __atomic_load_n(&s->hdr->write_off, __ATOMIC_RELAXED); + + uint64_t need = align8_u64((uint64_t)sizeof(replica_rec_hdr_t) + (uint64_t)len); + + // 简化:如果尾部放不下,则写一个“wrap marker”,回到 0 + // wrap marker: hdr.len=0, seq 保留,表示消费者遇到就跳到 0 + if (off + need > cap) { + replica_rec_hdr_t wrap = { .seq = seq, .len = 0, .flags = 0, .crc32 = 0, .reserved = 0 }; + memcpy(s->data + off, &wrap, sizeof(wrap)); + __atomic_store_n(&s->hdr->write_off, 0, __ATOMIC_RELEASE); + + off = 0; + if (need > cap) return -ENOSPC; // 单条记录太大 + } + + replica_rec_hdr_t h = {0}; + h.seq = seq; + h.len = len; + h.flags = 0; + h.crc32 = 0; + + // 写 header + payload + memcpy(s->data + off, &h, sizeof(h)); + memcpy(s->data + off + sizeof(h), buf, len); + + // 发布 write_off / last_seq(保证消费者看到 payload) + uint64_t new_off = off + need; + __atomic_store_n(&s->hdr->last_seq, seq, __ATOMIC_RELEASE); + __atomic_store_n(&s->hdr->write_off, new_off, __ATOMIC_RELEASE); + + *out_off = (uint32_t)off; + return 0; +} + +int replica_shm_peek(replica_shm_t *s, uint32_t off, replica_rec_hdr_t *out_hdr) +{ + if (!s || !s->hdr || !s->data || !out_hdr) return -EINVAL; + if ((uint64_t)off + sizeof(replica_rec_hdr_t) > s->hdr->capacity) return -EINVAL; + memcpy(out_hdr, s->data + off, sizeof(*out_hdr)); + return 0; +} + +void replica_shm_close(replica_shm_t *s) +{ + if (!s) return; + if (s->hdr && s->map_size) munmap(s->hdr, s->map_size); + if (s->fd > 0) close(s->fd); + memset(s, 0, sizeof(*s)); +} diff --git a/replica_shm.h b/replica_shm.h new file mode 100644 index 0000000..27080f1 --- /dev/null +++ b/replica_shm.h @@ -0,0 +1,59 @@ +#ifndef __REPLICA_SHM_H__ +#define __REPLICA_SHM_H__ +#include +#include + +#ifndef REPLICA_SHM_NAME +#define REPLICA_SHM_NAME "/kvs_replica_shm" +#endif + +#ifndef REPLICA_SHM_SIZE +// 64MB,按需调 +#define REPLICA_SHM_SIZE (256u * 1024u * 1024u) +#endif + +// 每条记录头部(放在 shm 的 data 区里) +typedef struct __attribute__((packed)) { + uint64_t seq; // 单调递增 + uint32_t len; // payload bytes + uint32_t flags; // 预留:压缩、类型等 + uint32_t crc32; // 可选:0 表示不校验 + uint32_t reserved; // 对齐 + // uint8_t payload[len] 紧跟其后 +} replica_rec_hdr_t; + +// shm 顶部元数据 +typedef struct __attribute__((packed)) { + uint32_t magic; + uint32_t version; + uint64_t capacity; // data 区大小(字节) + uint64_t write_off; // producer 写指针(0..capacity-1) + uint64_t last_seq; // producer 最新 seq + uint8_t _pad[64]; // cacheline padding + // 后面紧跟 data[capacity] +} replica_shm_hdr_t; + +typedef struct { + int fd; + size_t map_size; + replica_shm_hdr_t *hdr; + uint8_t *data; +} replica_shm_t; + +// kvstore: 初始化(create/open + mmap) +int replica_shm_open(replica_shm_t *s, const char *name, size_t total_size, int create); + +// kvstore: append 一条记录,返回 off(相对 data 起始),用于 notify +// 单写者设计:无需锁。返回 0 成功,<0 失败(空间不足或参数错误) +int replica_shm_append(replica_shm_t *s, uint64_t seq, const void *buf, uint32_t len, uint32_t *out_off); + +// replicator: 读取记录头(不移动游标),你也可以直接 memcpy payload +// off 是 data 内偏移 +int replica_shm_peek(replica_shm_t *s, uint32_t off, replica_rec_hdr_t *out_hdr); + +// 关闭 +void replica_shm_close(replica_shm_t *s); + + +extern replica_shm_t g_rep_shm; +#endif \ No newline at end of file