Explorar el Código

ZOOKEEPER-464. Need procedure to garbage collect ledgers
(erwin via fpj)



git-svn-id: https://svn.apache.org/repos/asf/hadoop/zookeeper/trunk@944003 13f79535-47bb-0310-9956-ffa450edef68

Flavio Paiva Junqueira hace 15 años
padre
commit
38592a9e79

+ 3 - 0
CHANGES.txt

@@ -65,6 +65,9 @@ NEW FEATURES:
 
   ZOOKEEPER-747. Add C# generation to Jute (Eric Hauser via phunt)
 
+  ZOOKEEPER-464. Need procedure to garbage collect ledgers
+  (erwin via fpj)
+
 Release 3.3.0 - 2010-03-24
 
 Non-backward compatible changes:

+ 13 - 3
docs/bookkeeperConfig.html

@@ -290,8 +290,9 @@ document.write("Last Published: " + document.lastModified);
  	   </p>
 <p>
 <span class="codefrag computeroutput">
-		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar\
-		-Dlog4j.configuration=log4j.properties org.apache.bookkeeper.proto.BookieServer 3181 /path_to_log_device/\
+		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\
+		:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\ 
+		org.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\
 		/path_to_ledger_device/
 	   </span>
 </p>
@@ -309,6 +310,15 @@ document.write("Last Published: " + document.lastModified);
 </li>
  	   	
  	   	
+<li>
+ 	   	
+<p>
+ 	   		Comma separated list of ZooKeeper servers with a hostname:port format;
+ 	   	</p>
+ 	   	
+</li>
+ 	   	
+ 	   	
 <li>
  	   	
 <p>
@@ -331,7 +341,7 @@ document.write("Last Published: " + document.lastModified);
  	   Ideally, <span class="codefrag computeroutput">/path_to_log_device/ </span> and <span class="codefrag computeroutput">/path_to_ledger_device/ </span> are each
  	   in a different device. 
  	   </p>
-<a name="N10074"></a><a name="bk_zkMetadata"></a>
+<a name="N1007A"></a><a name="bk_zkMetadata"></a>
 <h3 class="h4">ZooKeeper Metadata</h3>
 <p>
  	   For BookKeeper, we require a ZooKeeper installation to store metadata, and to pass the list

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 1 - 1
docs/bookkeeperConfig.pdf


+ 99 - 6
docs/bookkeeperProgrammer.html

@@ -226,6 +226,9 @@ document.write("Last Published: " + document.lastModified);
 <li>
 <a href="#bk_readLedger"> Reading from ledger </a>
 </li>
+<li>
+<a href="#bk_deleteLedger"> Deleting a ledger </a>
+</li>
 </ul>
 </li>
 </ul>
@@ -292,9 +295,18 @@ document.write("Last Published: " + document.lastModified);
       
 </li>
       
+      
+<li>
+        
+<p>
+<a href="#bk_deleteLedger"> Deleting a ledger </a>
+</p>
+      
+</li>
+      
     
 </ul>
-<a name="N10042"></a><a name="bk_instance"></a>
+<a name="N1004A"></a><a name="bk_instance"></a>
 <h3 class="h4"> Instantiating BookKeeper.</h3>
 <p>
     The first step to use BookKeeper is to instantiate a BookKeeper object:
@@ -391,7 +403,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
     
 </ul>
-<a name="N100A9"></a><a name="bk_createLedger"></a>
+<a name="N100B1"></a><a name="bk_createLedger"></a>
 <h3 class="h4"> Creating a ledger. </h3>
 <p> Before writing entries to BookKeeper, it is necessary to create a ledger. 
     With the current BookKeeper API, it is possible to create a ledger both synchronously
@@ -537,7 +549,7 @@ document.write("Last Published: " + document.lastModified);
 	The <span class="codefrag computeroutput">ctx</span> object passed as a parameter to the call to create a ledger
 	is the one same returned in the callback.
     </p>
-<a name="N1015E"></a><a name="bk_writeLedger"></a>
+<a name="N10166"></a><a name="bk_writeLedger"></a>
 <h3 class="h4"> Adding entries to a ledger. </h3>
 <p>
     Once we have a ledger handle <span class="codefrag computeroutput">lh</span> obtained through a call to create a ledger, we
@@ -647,7 +659,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
 	
 </ul>
-<a name="N101F9"></a><a name="bk_closeLedger"></a>
+<a name="N10201"></a><a name="bk_closeLedger"></a>
 <h3 class="h4"> Closing a ledger. </h3>
 <p>
     Once a client is done writing, it closes the ledger. The following methods belong
@@ -730,7 +742,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
 	
 </ul>
-<a name="N1026E"></a><a name="bk_openLedger"></a>
+<a name="N10276"></a><a name="bk_openLedger"></a>
 <h3 class="h4"> Opening a ledger. </h3>
 <p>
     To read from a ledger, a client must open it first. The following methods belong
@@ -842,7 +854,7 @@ document.write("Last Published: " + document.lastModified);
 </li>
 	
 </ul>
-<a name="N10305"></a><a name="bk_readLedger"></a>
+<a name="N1030D"></a><a name="bk_readLedger"></a>
 <h3 class="h4"> Reading from ledger </h3>
 <p>
     Read calls may request one or more consecutive entries. The following methods belong
@@ -946,6 +958,87 @@ document.write("Last Published: " + document.lastModified);
 </li>
 
 		
+<li>
+		
+<p>
+		
+<span class="codefrag computeroutput">ctx</span> is control object used for accountability purposes. 
+		</p>
+		
+</li>
+	
+</ul>
+<a name="N103A4"></a><a name="bk_deleteLedger"></a>
+<h3 class="h4"> Deleting a ledger </h3>
+<p>
+    Once a client is done with a ledger and is sure that nobody will ever need to read from it again, they can delete the ledger.
+    The following methods belong to <span class="codefrag computeroutput">org.apache.bookkeeper.client.BookKeeper</span>.
+    </p>
+<p>
+   	
+<strong>Synchronous delete:</strong>
+   	
+</p>
+<p>
+    
+<span class="codefrag computeroutput">
+        public void deleteLedger(long lId) throws InterruptedException, BKException
+    </span>
+    
+</p>
+<ul>
+	
+<li>
+	
+<p>
+	
+<span class="codefrag computeroutput">lId</span> is the ledger identifier;
+	</p>
+	
+</li>
+	
+</ul>
+<p>
+   	
+<strong>Asynchronous delete:</strong>
+    
+</p>
+<p>
+      
+<span class="codefrag computeroutput">
+	 public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) 
+      </span>
+    
+</p>
+<p>
+    It takes a ledger identifier. Additionally, it takes a callback object 
+    <span class="codefrag computeroutput">cb</span> and a control object <span class="codefrag computeroutput">ctx</span>. The callback object must implement
+    the <span class="codefrag computeroutput">DeleteCallback</span> interface in <span class="codefrag computeroutput">org.apache.bookkeeper.client.AsyncCallback</span>, and
+	a class implementing it has to implement a method called <span class="codefrag computeroutput">deleteComplete</span>
+	that has the following signature: 
+    </p>
+<p>
+	
+<span class="codefrag computeroutput">
+	void deleteComplete(int rc, Object ctx)
+	</span>    
+	
+</p>
+<p>
+	where:
+	</p>
+<ul>
+		
+<li>
+		
+<p>
+		
+<span class="codefrag computeroutput">rc</span> is a return code (please refer to <span class="codefrag computeroutput">org.apache.bookeeper.client.BKDefs</span> for a list);
+		</p>
+		
+</li>
+	
+		
 <li>
 		
 <p>

+ 194 - 137
docs/bookkeeperProgrammer.pdf

@@ -5,10 +5,10 @@
 /Producer (FOP 0.20.5) >>
 endobj
 5 0 obj
-<< /Length 646 /Filter [ /ASCII85Decode /FlateDecode ]
+<< /Length 676 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
-Gb!$E966RV&BF6e$6>[)[sA.s30SI<*r6/OZj1%CAr;^$P\0LRbJQf4V\=)j'0)@bG.%>L`(F3GdJFl;-jP^:1;^rT-Gl^=#f?O7:ce@sa1u5;Z5pM\XgS0$=fK(i([)m!PQ(OGK<hq'/*FFM\Zr1(+s-#9?(df<q_XU4Vi!bX+W3go.!,DF8&pGTIt_qER#iaZbO6B-PS:s8PqLna7^lF+[[Y;NLu<57K'=s3-,@$X"seXW4UE5%KCH'6=!lhl%MYe_O1!e)b6Ksei(R3ZP,&03E1n"p<qe:.!](t*DKo2BAK\jCO)8P$f%.A@Zob[7B":FVBei8G0@@uW%]RoN(GuF(=%8b%c.um)MJ?+=FIZA+.0XaZpjVAY1'K*MFqiRa"[CtO-isU$PF5Tsc=-D3!t(1[AL'A=iK3P?,_!U1UUrJ[?&\._cg;mA.5:*?Kcl[1p^(=$WdTL6_GB+o&:1>4\gWmgp^,hX*k"RQo^7s]J&X/RT^oTK*!KV\dI2)(+1G7%@u,I`j57^="YpFMdC3dP*#@b^$:@.8V8/W:L_,Y?J^U,YI-:gKIkl/S[I,=0K*pThMK.XWCoa(G\^*4KIB-$<QlF@mUEA3a?\ih4?<Yf;A$"L3[d'+QUC(tgrrQHOi8a~>
+Gb!$E966RV&BF6e$6>[)[sB.ta#IosD%D&J>M906!].g:'hU:Xp>o^-ajZ)eE>(=!?$<XTs!01"kL&%"L1gu4j]-uST1su9*>*s[S"OTiM&6=..EZkuG-tB9f4QQ,;I?(U1eEJsWt3XGVQ6iZ`Y@.JdYYJP8pPu:UAWJ>17Ke?A[l+jfV-OFit@n*')sIEk(!c+_t2ljQ")g<^07MY5&XD5A7taM4H9^@a!6t3"&]1Ok4=,A%AtT4;na(I<NB:>]A8%T>kt'J>ALe--3p(*)G60O!uio#U/1%q-\l19AC1i^.]3]bTCB,O:!oB+0V3Hg(="K*W&[L`al5=Lj"uM7C8O;A?G_tn-ZTUlfZLLk<$*,n'n/c+*%$-%Go!8""=097$WD!X0$D[Q0PiN#aPJt:H?hb>OuSCG:4ZUpE>XP%E7Luf's<I/HR-f.i*cs$409'=R"CgsAM:Ys8ASX?c[[]?Fo%g<6Z<^QbJN-XPubLq%f[Ea8:ZTXQU(`\Y`-+u1'nT_'&L`2#.ikgD$FVn*(@QeUYjPJB0'9/S3SjRkk+$l:l_nN<V.kHO%1P.nA::8Yp%g7'B'od_9kN"-\njtp5cea\&P"pIS`e@757Q>Q#EKV0)*?)[;T#U*X_:ZY17r%%\FurJWnZnesL4HN\,UWs2YhSoY7'2'^5~>
 endstream
 endobj
 6 0 obj
@@ -29,6 +29,7 @@ endobj
 16 0 R
 18 0 R
 20 0 R
+22 0 R
 ]
 endobj
 8 0 obj
@@ -102,32 +103,43 @@ endobj
 >>
 endobj
 22 0 obj
-<< /Length 1815 /Filter [ /ASCII85Decode /FlateDecode ]
+<< /Type /Annot
+/Subtype /Link
+/Rect [ 108.0 402.141 206.144 390.141 ]
+/C [ 0 0 0 ]
+/Border [ 0 0 0 ]
+/A 23 0 R
+/H /I
+>>
+endobj
+24 0 obj
+<< /Length 1902 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
-Gb!Sm9lo&I&A@C2i+UHT-ijq`Qs8p64`1d%A"?ft5YI3WQm,OnMX13:0),U#T9;s?:1c6^K\cBQI9>hk\')`DpDabU4(u0-3,#oHaFQPY"V/cPSr8HkUZEQqGt%3[\tMgB?[^2ID&2R6;6n`9Dc*dgUY@VRrCtFebc]?#B_guRo5a@[\5s4PMora!@H%+).kPYO^rHq+;'s]6iqLEo,"E3<'fha#A[&Q$oh6ej+f],;gB1Uj8!Jop9KCfOiZ#cP3ERtqhU#1'``fV#8%(i<DW?X`O&s,X8R@'A&VWZ!%)WL$RfOlM%!oqUl91k\>eVRTc!.'QR:`I/JSUk>anEX?E:A8?l,$o-gm]*fQ\oD7_XiJrC!HK,PESLPirK0M-OKDbf^"e)Nd^&N3bYM$L72p<`mXR[7-I<roG-G/*!@n8^meui)JYSC>]3CP!=P.fM'?=O^nMHmVh^U1J-A@.Ws&F/?;CmCZ_@0tFPiHi`a%FETVLX$`QHDt.$Gj5A3S#\p'X-;9EOl,f]uQ48L_AVVN%:c[7J>Og.iB?2i5t,i,p%CV>=e<2MMF\dCWrdKT,-A8W^*-c?baR=a?@r=LNqgbB*(aGHlA_?/gB7$(>:(OfKf]]M/AXRY2TWq:'Pmi"Wnm`:#c!*=!!.'rRf:oVH:22:qAGCACgOrZk%lJ_tGIZ%jN6Q=Od/8Y..-0W-9kJ<b&^IT,Qh$RJV)YFrWMA2=1\CAdq))oEbE;@Nl]o/Gg)qkTZckFPW^;SR<$ZaA?M-Zt_dCT(C-UB*;5]kV,]W,"kIEe;)F-8*dJ5W@6O2]5B)WYV*3TehP_&!,1Z^f?9d7NH.O1kqIb-;4*.:TNSXiUBF/^&r77TMSLrK[(6J%5lO*#-A6*WH-$Yi4,.od54j8>LhsdqQ1GQmA7Gq?8CLu]p&m3'il^$L-$h[:eXHoM<.KIe4l1hKc]B14Qqp-,as3)F#i%L202VYC`'S72&q:u^=&A:E`IL'%ltQ\Q4FLKZ`Q(=ip[M^FqVQ?bLc#-HO]98)*sdHECQ?ff,PL:9[90I.YUT0a&S76q>;k$J=tK/LZ;#IXh^.hFM'hF4[BN\.]31sQe;n;jj2P)$FlpN\K4hLTDr'96P60:LRO-\mm''Qn/oEPMrtSo'qQ2kRl[d7"8U>&nU8U_hFikrB2bW`fB535onFiM&Q"-n)k"8Gbn0::iCtp8@0XkZlQ>--]Fa<ss8.j6m0:.6K]ch2Rc9cnZ&)?Xr:>%\_N.83Zg;pe4\UXaV7r6u7i/M*2C3BIW2\^BT+u)jK\"Vuf;U1!Y9*E6OXL`nXNE+a5$mYNA)lhak;GkaRq$8^&DP=F9Fb[g3#j'f@<KHSA=Qk<<Bnp&j5<UhG[MV%@Yj^e1@.R2h1\(J'<a`_NM!4=]ok22T@GuVg>[.TJ'`h[3.emA.:'X0ibfPZM2^mj'q"_=I?u&$)VC=_r.=f%P!J1_$AF)ib_ngG9gA*@OMF*HU0-a]Ii!eEpHO+(`Zjk=07I6g_*SQGHpS"$&1A2DgCY/GZ7+Rh&6B-C8IS)iHFrnI4^Up#KoiSBYUicHpAH;^F'Nb$2)NV%gHVr'Qh%l"kA,M@'FD8OL4r,;$r$`]E*!>T\f]8KDP?\5\51N&"-BL_oQKZ%#d_*Od-H_>>1tRP[OTr:Zl>Oc't^6T%R@_AdJrgc+if+t.pNd5=R_d6f5N5l1hpie37W:>(IPaRN';n[T,[P66((1jWBUlhL\E@Rm`GllX13`M(ssSn3'r\k<hUFZ.Z8(*IS)Q<>?r+J1\^,g=dQT7)eO)k#:4P2N+H-XXc8Y0?[4[/pA~>
+Gb!Sm9lo&I&A@C2i+UHT-ijq`R9T$tT!X9KYthEJTI!-<9T^er`H?WX(]4>"&u;=03h=JS#)(h,J:5%3aLB@3:\Ph@%m+I8=ZC*,+NT+`"GI?0q4<M$l_EP_rGb9q27fJTc<l"AZY^cNpMmcEPHSu:;kr(uHhgZtK?17DT4n&Dio>(L(V#eC%u]/Tlf#YRO]P]@0Sa/\>a,Wg]_H>`/'/AkBMHbt7N$AOc0L3aVF/kVd+8N0+AP`bp+YTAO,0tK'BJ)%EV,,0>;4WZ2*UR_l>Ts7%"#Vkrfe10Pa6;g<lZo>^c*-M1;R@+XKUJ*$HM7TJ^qDCg6a=d.MfPQWLrN2lk#!2jO8h%::3#6`%DMQM$qWGIaWuD>qRIbf#.XlN(t!&3&&rW#9<Wb[lW`OG(tljA7K?MPTk2r6&#_eH4E7XADk_=ljOWP7'*jFML^E/r'V.$+N-Pt!`'7YP5kuIgfF[W@D/6FJ7h4?$0\';2iN$4_iS'H4,UG67T#sm*fInTdI[f3!LX'/3&&t-n<6IlZV4RjNGFs8BUV[BMDpAIFPug4KU)CGBsra79kuAL5+s/]F:tD<TXS6n<*&,/*6ZW(@sLg%E>NsLk7S$$>0m\iP$C.i@5\..ckb+V/#Lb:J<TcE,lZ.Vcu[!q;K6GoTTZ<4<*\h`eF4nQr(3!D"2F"!@Ll2S/BQ14OZZ,8?qsL`!3>O*Ff.,2(J:?0?:03+LiiVg<VXg5B>_2aWLAJ9qQi3G?`?*<\LU[21cO74/C!kQ8tBPH)(Ls8BYY'Qmol+u1d*'g3FV-\',PB`T\FARX,&*@<<H!Nd$_foL<&O=i3L:J<X25!XeFacag8\RC,Od=*'T38FMLTU'KR_1d!;@VTd![`i$9%6EdDp](E;1Q1NB)q..(3ST1'r!kcPYO2FB&!XJJ0BB[YJk?r.1eZEpC#")0R`<0lZm=UL\1'[3iK$u)oWmPFnSCY,9]0CZ6iKD&`U5HT:9b2IC[>MmmN1n,P+g\8&_rrpDXRZ5(Z4We"ZUtN\,-PYhmcAPR0Mc(PE89U3an&IbR5Q0?I\/7/`]Bs>CU1mufo/Ep(hff;G>.3P/:#0\;bI9Gl7&ulocf"Aj50C^.'_X>73;_DIjZ6[q;!r?YEu(eb2OtpkAX4/(]5S#Y[/iH2T9FL'Sp[I!rTWSZhBA.nRa2>'Ii!D#FKMEj>P;7!EGbRBn!,ksEL+=S\/>!Y!6)1]s7Ej+4Ek29c]tG8jak)eWK*j4X>qFGPfBu7W=,0%kX+'@G_-e&i@I\J?'gZpUA[9e.E!CP6()N]5n`JiO_rV:^Lp\6cj_3^(LpM_f2R]ON99.B02iJ^Pa3N>NsF=T9UMAIafMCu\PQ41,,^-`EX/qW6;?RN=tRgVQ`2CVDnaHgQ7.fIXKF-Y4^RPu@kDiDCE!u)bq[V[']"UF0+N<]3#j'f;16=;A5X7U<Sc$8j+*W&'Cj.-U/Vfn.o]VDrS9p"`s](=::-)I6G4!fih+a^Fe+#Uolk.iQc(("+1'LU..;=VRYp/iP(@ltdl6Jhl$Htm^EA"W"`u@o8Ec\8..RbAo+HcHn>o#4f)Pa_Kg9_NhbFkijLkPWo-+\\rj]rq<'Uc&7nd-F$;s`eDd%s4KYA_OUYmnmISX$D>9Teg"WA/^Hi*N,'a:a"i!()9<VB4)cD>pPmHIdp5"3gSlP:O]0K]IMLZY/SYl=qB\Qa=XL"rTil2es_?$\I(=@RSb0rT68GV.,ebdMEB#s:4.CH?W/IR=8:qF:GVX%/0N.5u3Cki%%NgqH0\@A$J7F2Y'("'u%nHVAdA&B8\Q1DG)<:""DTQlY&SGe:";*%p7U_IGunW8e"qe3"K2_2#&$<o_5:;nb/\EBSB8*Rf.r`E4oh&iHVl$Z.Gp%Vi+/H2[j$T4F,~>
 endstream
 endobj
-23 0 obj
+25 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 22 0 R
-/Annots 24 0 R
+/Contents 24 0 R
+/Annots 26 0 R
 >>
 endobj
-24 0 obj
+26 0 obj
 [
-25 0 R
-26 0 R
 27 0 R
 28 0 R
 29 0 R
 30 0 R
+31 0 R
+32 0 R
+33 0 R
 ]
 endobj
-25 0 obj
+27 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 633.666 234.648 621.666 ]
@@ -137,7 +149,7 @@ endobj
 /H /I
 >>
 endobj
-26 0 obj
+28 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 616.466 193.644 604.466 ]
@@ -147,7 +159,7 @@ endobj
 /H /I
 >>
 endobj
-27 0 obj
+29 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 599.266 235.644 587.266 ]
@@ -157,7 +169,7 @@ endobj
 /H /I
 >>
 endobj
-28 0 obj
+30 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 582.066 189.66 570.066 ]
@@ -167,7 +179,7 @@ endobj
 /H /I
 >>
 endobj
-29 0 obj
+31 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 564.866 193.644 552.866 ]
@@ -177,7 +189,7 @@ endobj
 /H /I
 >>
 endobj
-30 0 obj
+32 0 obj
 << /Type /Annot
 /Subtype /Link
 /Rect [ 108.0 547.666 207.312 535.666 ]
@@ -187,172 +199,205 @@ endobj
 /H /I
 >>
 endobj
-31 0 obj
-<< /Length 1938 /Filter [ /ASCII85Decode /FlateDecode ]
+33 0 obj
+<< /Type /Annot
+/Subtype /Link
+/Rect [ 108.0 530.466 190.644 518.466 ]
+/C [ 0 0 0 ]
+/Border [ 0 0 0 ]
+/A 23 0 R
+/H /I
+>>
+endobj
+34 0 obj
+<< /Length 1941 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
-Gau0D968iG&AII3n7^--#QYL4R%@j=:>I1Z1tK$h-jPW],h<YQK;97Vf,&g*=O80:VpiaI,CnFc^@ti:cUKk"dGkKoC\@FN'Y;A.I,A$*H`[)BL/AbH)0I3K(8F)`f<`lZgVCX)I@I?.DGB;oJ(SIK4c2R"SCuKhG(C5kQd-OJF1R`2*Yh8TeiT#nRI]I.96L*C1],uT'4iTaJtl;JP0/lC3LDWYRIUo@(rM=qf6ekif9bo:@LC&[67+hH)hlYRYD%5r_"j#6/%q>bi&;e&Gg,bAP0\;XEFfMACl-'L?V.L'>W.*`/u;N&[oP:"G=+cZMB>:=[$*.eBBZT6H(HQbrf_*\og1nqo&hR\8<J`a:P"?*+Gbt4^`Ki)!\Y:#To\\/iKZr4Yr@'Bji'\?JSGRa$@&4AXChA'2LH*1KOR?KDr)]!)F_7dhJfhu(4N26N8cZk5!dQX/_cUHb1$X`Z:.98^`LuVn5+?hIBUlu*##15])d$m2N4Bg^h-Y#dNhj5I(/8-Z1d'n;7<QshsNB4DnaILOt-)6T6Q[Z-i`Zd]jlG=Cd2)CkIEWBIneKV04rNlE+u"HJF2@,!$?D^T'r$'^<\G5J[3<[fB^Ec2a:cc.h[utV'(?7Qb0?W;O4qH0-Skshq_r"me)@qmXW?Ib?WunrJ!tJSV?GVhKXtrD+WlCYQ=3%GMH(9USRS.J7.$Ma>8Z\+Y`1V<c/^-\]"n&\p,oDke+KsDiGs(.p;#$^RS7aW3Yhk8h5d/9L#+HfaGA:]dd*s!\>Ed+j7!ectRWiVm?8$l6qO"DA74ooP6f]eIrCL?>UT]2YSfh"Ou`mk=]1dUDL?*nf?@[hdKo?RS<,!IJS(Y#s)cSlD*ik#,<<#S(]Q,11`"GdQj"IG#kp^EXD+N!Ad0@l7Ps<6(c,cY$c1CS_/Od$m%'J.Q9Cn;k02q<o,t*lA@Ah;baYLV<Ke0C1U@E0q_-=d`uOs&O]\lp*:]h@504RFVi6n3g9h$o%gQ"]%NBq*UEOdJhF0-r68a0!m-?uAj$?nYRjRr5nT%AM.au70aCNi%rAJ6i[J$!#cSnUGRXE#2m7rVG<fT:n?L`E27%GI=&GA$0W&EW:_B&)eGoX!AT</bYK57d2dc#kmj?X.Ds!BO@HEH>J/&qiGK!n(kh).`ZIgk1jH!jr@<NNn#+X*n?tQAoA<![:qd<kmV#<kU7Qmhga<^e"9L]<ofIeLt'$4%TC4JGF*rm0YkTp)PJ.*E2KUaOj(K()1d,Y6JqL$B0_oLbl9fNaecru"7@AH<ni6<-u9j>OR0kEanY0P`?VKpDJpa:2S$Pfd\eDS,"L4m&/7ZF=G,TE5!`f$P=3"Ad;+fM`ApBmcY.s8IJ*8P+qCIj8u/dXQRr.KWh[2Ut$9jC-*fVCBn33ZpkiVHOg)dVa)<8P/1?_-q(85)CFTXM\GYFNIIPH)h.Jo>i^hl:H$%$4R5",Ofta,JkC4V&N&Nn3Ncq:R<3Hmife!`qQ1k2f<!Ru6L2@]4oX2F_#>g;I6n+u"j)j+!Z%ZUjb9I^0(i%-@SsjI4M@lE-"227&@il"7H`_3([oT]$GUbNFkF==)ql:c&Z\:*phh,p-PFP`>8t#eE<+&3N6`1quj6NH,NTY9:1lI%=uJp>+Rn24nL+Rac&-<F%>HY)ET8J:j&u3+JJt*dQiU?Vqf<5M_iQ"?bR]7/p8YLB:(Ai\Q-DU")]gU$Vnu=Cej;QL)b9pt8JJOuTHM]J*lH.Dd@;4`1J(]*1B<0&H3Z:`>CApI-?cAgGdear6r=GN\6c]5a/VW'\ip3P1*OlG7agG]:Z'a[-MtK3#30d@)"U;4n\J)ah2M9EL9+GBD%G$@V&qQ"A(2)2d7V9\,]eW56!h(rEL`&N/t><=<o;`MCc\]tP;`@c&B#B'33Zfs2[p&0PbC`+Dm(SV&fG\U;i#P;:q.p3jem~>
+Gau0D968iG&AJ$Cn7^--#QYKaUaKBS;`DfDNA^)Hb(690M)@`C+DJgno`ZEM(,SS(l#\]N#U";qn,4$Re$GP.g#Ern<pK_^ZcGS<j86Rel`p<\)b,5i1?qEubg68J]08h`s3uh]h?FIeC2:CCEuQ$!rPMB'7fsH6i_2;V[r[K6\o?MfL<KB\o!hBbQ/7Ajc\sMX>cQ91Sa#T$Gt<T400#og\gTCG@La`e9Vsr)7uZD-Snl%SP3Ybb1,T6pGpuZuk`&L(hq(1WI,KCqje^g-9CNl3juhTk&^+fKYGAT1+1K1;j0,gp""n@SQ;ga3R6.I;MRsSMKAm-`2=8q\]+ahhMP<Z))?38coQi-_(<(?dXJO!,<Fim5!YE;i).8M>D1S#\1\DRQ'jcbK'0F+@)d]\d!iS$?R=GNW`>Z1'Dke,b6mtNhqW9@rY#)cjP;PjOA`8Ea_C3N(jV%c6hQ_JHUJ,O_5$N+O#jak%r")<oe+_Qi^bKhp]c0hHA`EqBfX'73o.3TM#N'AXHu/`T>F[>bkBFP?_qT+9o<]"@r?n0QpZXp?;XYHp+1mRLa&,X1kca6.(Zk:7$SF$]$F$'cQf-m^/rJKEg\9A)+Ahda'me]IiT<YI[q.%0]+bD6I(@En/nMFBq#XI]q;$J-m9Y9%m#H>'^!$ZJhQ=?Lg0*''ie7Lig6'Sb@3aXJDV.f+U87D+Lg\lUa>8Z\+Y`1V?>\gY\]#1.\p,oDkcDLgDi>l<-s:-u^Dp8-B.E4RV6lsV`:W(EPuRnX8-W(sHNdM8<^Kh+;k`7:GbN:R=/hrC%_5Fp=YZueNDr\1-jI(n=kVT>BG+.FX+E!T'oZJK[EEc%7t$/Dn`adtYO7UX'2$VKK2EFRY;7"!C#%9o0p==&&X*Ef%(*?qQ&lAecPW#uY#KV-.L:b[hKB'L)stT[r+,;Ad8RU'iS*;(5dp7G\Xor`=';E"QBa:T-<.++lRE*<WCtqO9g4<q.a=U("#hbX7CDDjR6cVV^dYsVR\H9gC!a,VY:f%fMYZ-l!A9JHXCOM&0FA3HPs$N.O[&A@q).+29'q-<[Sf5a$POZm@gnDAKicO"@E0BcQr8[o5-:6T$bhS#XFr;[@tffM/?B'F,@)'tkOapBrd",.me6)6qW#ie![t.?0bCQ5LZknr#oF];C-WOR-C+M68gV\6,M%BDq?>(oFb[!&<Gr'gL4.btKk.UiW=G8e`afd9JF-jP-]p%RWWC2)rrJ3YFWgP,J.*E2Kq'RikAg%md,Z/dqRk/"rQ"Ja9fNaecru(9EMQ$Ni6<^09j>OR0kEanU!D@2VKpDJpa:2S#8O@XeDS,"L4m#F7ZF=G,R[=0PPJ<p<!J;-"AMo*?GTTRV/H<nK6s\@9g,ZR8^Oa#-Oe5#rLb$GiXo2#a.P;Y33Zpsj8*>W(gZF*<8OT!?^(4385(8&TXM[\W1:_BPGub-JoA(8hl(<"%$4X7!snF>7^(j'#EAmVlh0ZCCmHk@(,eR3/"[FFo!Y)`7"&&qf"idCOk6Kh0pejF9Hq[T?_j_b<rJU3/]#@/o70ta:$I#t<[OK.fuN8l4^RX982O/iE!W?&dmcj/P43TB)Z,(\-CKf=+(6X`NUm5X\j]g74@*4/4'*bg$P(K9+g`5;S`uq^hI*(H:GX@ml86AXXr'j!`WHsk_.cc<0[=.m^N,(4.1XatXcGOFT'n[KpaXTW!@9)_M*RP,AY))&+)&P9Z\e9q>@lj@L>%g/;.\[>+TkCM-B[\81JlmZn;25cSsT?&GhBV]@p-5bM*=uu!+!?$f5KBF]A+<>FAL17,-664?LAo*YuS*N6Xe=Jp*F$bj!kDc_JX-[(PO.((jJQkN1n=*N_4Cep<?EMT4PT;2b"7n-=[>!H:?>jUK8J_BbsiF(?kG)=I-Q/l*NO]U<4:saG0au4!_7mk3`;PH,8U+*hAPSrWUklb>/~>
 endstream
 endobj
-32 0 obj
+35 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 31 0 R
+/Contents 34 0 R
 >>
 endobj
-33 0 obj
+36 0 obj
 << /Length 1922 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
 GatU4hfG8H&:X@\_.,7LlB":/\3;4P[b'iioPWZtV@N`=_hA'o\Z,W+>JR[J(_N[:9KWTfX4?XI]:X2W?G0RH^9+??L&V[afHm[6"9JGs]RPCT4[pX`3N[Cde\A0>B*CVg6tl:4n#8YlHrt;fmNCT-+*C%=*Y97ccMGraEco\F^NR=Plb>\54p`55W#Ha&!r!h"WZNShIP(Vd#Gsc6>s#7C@-<g%O(hn![P%623r)RK8rkoRMZhM9hGm/n79QS&Ic'MGVX@tboW+$D7k,uO8>L^#>ph.&LpBFk7('LnUN1Y4pV])+8,VCR7FRJi.TB9?Fg2$hR"6#u.TB.iC<%IEJ?Yg"okE[D(f<nW^m''r82,011#6^l^dB"1c$U3Ed>CGn,RTg:-Vi.,.*MF#Be+n#ZO<!QgLBR&R>1FH6A#c,d\BjC?!I!6R;oV"&bcFYC;KO1U^uPIeI]B,H?E')6]Y'd7Wjr?#a[JQ<`E9+6,7sn]6TI-H/Q4'Gp2)H-e&ZfV82j%B]E98%Y.E:;\F+3RejQed<;--7dTlm,*Rp7/!ke/]TB?O0GcA5"e[X=P@,k;-V>'f`hpo5HFM/^bKS:bma\s;N1/0DdAf33EA&O6B_#)+W4CPjF<D^u<FK@7+[):G?".0U1A[<d=ECsT;K,oAmlIc`c=RDrS9W'p#t#Kq@u\rL;jV(oACqC2,-Nf0fgM,`T$W86$DGiYGY:hGBX^Ad,0_E*lMBI*ap+"T/IQMPq0R)1T-c8<@HL"K0N5*9k]95gn/EH^he?_jaSYqH^%ampOko@:kT6B?E5sr!N]E%dQG!CQm-h-@]ola:l7\Q%ir3,Bqg<YRo_;o""hNMI8nRO@Up:lmPLU\K@6V\L/mG=L67jB&\AY-q+;V[]25L(S/2jUI30#.j@2?P'd"f%Eq_rSHL9@W\I^<!/m+_#Wij$R(FUZdJAn%CN;n9/-g%lXe)MR-MDetCE&n&RAm]W'WMU#mlRq^2T#-*IK5"Rd[kAEN_+ZJ4T[Qtjg9RS8<6\V],eG]'0kAntf8T`G[F>A.Zo@%7J?5FJO`dX2B`Jf2@LG88cJO/LdBnBrE51$KSP^4B#]>3b/6si\pO!7D/2Cuu\F#3>/02A0c,%q$WIbRGH7UV&G3\=Sa0i22c<n`BAh)E^ZKO"2;(Zc^G`F@]!/qT\N$`T0=j@EZk3%e/X;h(5enJ`C/d%!<Whj5=LXN#KMmt5:_c/Q:L"4"b1'"6A/pWfbemlE9T*h`^"6J1Eq<7["=;2?tHB9Bm7L('N]+^"C8D^-qmMeX]"/1/.:9I5Tb@jjAS(rr=u`Db$bk!7'U?e6JP-qZIqc1oq!>Qo.n/hB"B'-=O+8D;;GT8ljVfS^pd8!?Y4q!*;G[D^&^O:jU:<4T7$iTsN-H7qN?@>9JZ`O:AAMFid:J\J1Cl(eRJ%GgaqdpLfCQ$/@ET"&'dVO0biW,3W_Mn0"#JW\cu>?]__F1K<IA^$0$39c?g>q^2T?^i\0.i^'eF2!@[NVj'K`!g5LYAkNtL;\3ZduIe03LomjRVEgucHIRI%Ir,o:4R0NiD<9U(*=T3=>-8^&+RL--h4GpjniF$1PIJEP;-IrF=MW\-\j2(USs&^="YTZTD'V,4+EYGIFKhZWOq4dW(aoSAA-D@ZG)WC$B/H<WT8<Hcs3QNdfLM>.^aPeTQ7\GgCq"jBqI(,!o%ZKVCl:pk_.G1Pf9E.[u^rhL0WqB6/KOg^mqG9;B>Y[l.oWp4#38"kO"/n)#3&FX1t;KIIHl(nSjNm$hO?5CSPgT-cU-[b)8@eN`&`!YjEO;Q,[Q&g)P7U:q.d&p;54j39?[K!I#a'*'6RMD;FR5@[dmI$_sE60M_:s6+tX?"$%8)2ac!>j1BW4Sj\Ln]WZNZ2Or2$&f]/fj'Z!$6Y"fkp:JPq7H"3nl*:Z~>
 endstream
 endobj
-34 0 obj
+37 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 33 0 R
+/Contents 36 0 R
 >>
 endobj
-35 0 obj
+38 0 obj
 << /Length 1691 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
 GauHL966jf&AJ$CE-/)m/J8\Wh:!Y@f^):3Ft::dk9,CnZb_G$H(=g0'k"*Y#+Xa.jbdOS[JKiE2n+^uVoA#;)0Rq7n&m8&OmDeVYJ2NeJ);pj,L?%R;E1`15I9+&"J1Z&3;qTElsQP0/ClVd+`d5\4"VWI&IteHfK%jP91%9ro>=`/V2:o[;+H/mn4;NM7uCD3T*X(0JObf?';X0DF$gj+kHW62.5S:R=9".[RJ"9,M-6rlBbigkjZZanQ"I"A1&Jr(/7^%VA@CpBNA8c(@O8g<q9-8fC+G<Jp.Rb86p&Y<;.OCb<@S"WW:!]Y!)*m%g7jf$!c9LCGcc>J!&7/N%N&'9em0W'1uA9Jbg/s.)c:dfT8*f4,/e/6$5aBuhhmeB?ab'MNY[@RE?=[Q%!%E8<9.fH#`6b+d@j7!f&7O;L!IhU:\NR_VII$>J5=cPbN-JpcVCF@9If9*9Ypm(:;hU^IR$`ZW@uF(iWYCP!j/8GH4lt!o!H!'DiJjgniY%47"TY,6c?^i$Ah%l(e-f8qXGkm\#%=1^?XD=pP[1=/n3X"`I=Y9='spubnWHSR[@)riGuZF10[@l4]H$AT.<d)qa-/#drR't2@W+jD^B?IjE2*N/62TSqE:/f54W.n:):M'g9IBR0%u;>To%S9eb]eG2:b7#1E<UOgpP^Krn[)q>OhIpfQMCS((VGTF:ZpnOO5X.C1UkG$&\KPJnh5rYOD]hF/)A=2b37*0LicHCi8cX69%:UjRt$E=q++]<_u6hWfbWHI=W`'RR]a+pIWADB\Z')=P?gf.X+<.Fq&a-3#R?r0f<[T<,4nrWD1g!^i>jU'TkS!=pNTH6c`'pMlG]fH8,_n9gZQ\2D68c\ZtQ+eRLEi11!r_<ji?'3b\/Si@3Nj*0qg0kdLTdD<\=#U@)j;o7U!%1L`.Yd-4<VSCD(Hd05-oM:Imofk`f('[A2ajBV)qbK/lNTJR+BOA>R^*DP[!)$:/O.qc>\D(h[F1r+AFPe4h65]uQ%M9bV3_f+au4jPo%;oVb<0k!,'Xn1d2ba(TM5)18I!.QT`g7l4mnGHISG*J$-=eOa"%;e+OH"s2?mFRD.>tsP%#Xr2%`hmf!kat#tRP]cdCKd_!eK5V+j(\^GRt"\)'%uuaJ)L-oJ&YVgM?7(h/E0_hKZ'VkpM%sn&HFpTSu9Okj(c(=DnG(gQ6a$Pp"j6$RNcu^_/-#7Mr5CHJ^a3*Tb.W7eBM&'eFA;\jR8YC#fS3NBK';KeX4!]^*4gj1^[H,((qrOLGgRBDF1Ml_.W_Gb\fP=eol9F>Gl&/IdNXoYTA]`1JG4d[sI4QZSPSm!uH[bV&-$5*)Yd?V['-$g0tjK,1`MpfNlsu'o#@eI;f!n3BnFb.t[L%W.H,?NMt@dV#[kpYJ?:NMsA'eBVf/MnkW0Jf'&3Cs7+\)%e.%-H9Pu#+:Y2o2[J;k1c<6$-e\R8:T!'ifDW6SPto(^!-+X\:#S-eO@^F_P@o1E)GVtH!XF\$S%>IdJPVg3(SSDMo<e7jGc=k/1["IG+s<3$Ds:G@C#B9L&Op$]e^YeJ2Que.,h%;`#"QN/jr7a6@R)O3[YE8Q5m#3ERmG78ML=Q>\epQIG`]m;R;TGB1'D%7HOtqVMWdOHXH"^V/j;,VCY"PeXU_uH4.eBh-dB7Z"N[mm//m@[=Goe95=GW=pj^\R$)R~>
 endstream
 endobj
-36 0 obj
+39 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 35 0 R
+/Contents 38 0 R
 >>
 endobj
-37 0 obj
+40 0 obj
 << /Length 1883 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
 GauHL968iG&AII3n7^.D-ijs.UaOo:;E*jI[5GWc3D^tHZ)1'WK];4QG<q,)Jg)Wom;t,R#Tso8rV#mb\+A;OI.m;n>&3p5@2@S8[QMlg^FiU&J)H8!O#pAkXQAf0g$MoC(4*nfbC=n8/^!"pHo86G.3&7`X-)HaTn."(\(9`C"_7JaqI7^!!MQ_2C'COV*$m`E-m9*_d7Nh+#q%!L.?RZ_TOP%fQ.uX%W4-M3`Cg/*d^?$L*q(VAkg<$Q2gQ`i=f.p>Me:nZ./!AeRlb^#qJc1Rk:k=e6Vjdt!-82S?3V6si3qe:U8iN2VBFnO@AXHf/CHcKXbm`W+UbY2N^Yg[FXE8/`amK7[)fS+*i8\R2K;^h>W)qC$a@0J?lJb%rStfmLR[$opJZT!+>T"^<j#<7>$V*Wan`j2iaGCE<pZ\EjRK)unm[Z1.<Znb4/$r+O7/:*oAP.dV(q>pg%>h^M_rhV8=f;jD#1-^EcI?Zq-&9n*g/I.oWA\kGn^%p3L'k`ampS/'Jib[>b+kh=FL1#jHL!q;3if/pfYq_9>"g2Q\Zsa.).@:-X>&hlT3aP%k'$)X?uG)ULu;$\']F?V?u=%\k;KtPUD[R:\<.2P,'ibngHT46(?$KBGG<]g;#\B1E%.$;Sq5)6mQ*1"jjMs.$%LI(Jr21liM$;i'Up.G6`muBZ'1un=BbLF)IlO(d.21]>lcih<m&'"`O*,a*<0.2@2]^C1G9Q)-ElA;a&C%-s'9)/5T>_*'Dh#%V=cL7Cabm/rDT>/;rN`=brUs8XuVb(9*56.s,jgOSJdFhjb5G3/^c3*lr]_dA<do3N[)@5f@Rbg]WL+&#&$m6>h\!oY3pD&9JnIKV<%YVeYO'Tam5a1r3`5EVct]'9/H3,BHjq=n,DEIgVJLJ%Hn-V<^7,qbiq9pTB9Up11_S-8&9QktblLC2ME/IKk"/W7GUNIp7q=2phBk!_`i%2aUqX825Q*KlJ-5K=?f;\i$]lf3CO,?V1@%aDo0lOB36"J>bae9!Q6M6&"m.f$%4;(79F?db2_(gQ1gAWg^/M1D`Ba\)U*.7jI5XE)FOhE4\anM+PmXJ&)#LEH3AQKmC*emiT3VkF[SLkn;l^VQ^rhj/p=@$15q03s_uagF,jAq^dn>0R+MqE#)"m?l+uK-c!ECZ@.<f`%qQNPbT7Hp_pKU<tQSD`BKX91<i^RR.tQ+mYXV9"S5r4aDg?U*4enI'dXo9l]35^N,GmMMsVr>X7nilBfa&e\a-_K9a^fe)0a>f1?ALcVjoXP.2C(X;IRlnE74d"2su,`Nc,mCZ>EGG"8kd0H^T=OPK1;o(r\e#`9`(H\YV9kq:AT>`c.:S>Jhg+`@Fm/#rk1fChn^AO:j+?`,A^A%GcV.E66eAaF%Y@m5FpOfVnhG*1"XD`MoEs)s$m?TiG8s;LLX"0%_^8D<6]Y7;ED=EmtAp#2*:P^oE_nNuo&B/GD4TP5B1&fVtnP3p?9I2g_]f0Sk&4Tbl2jk1VlQ[@L7X,]NU#UMhGGpE]ZG@M0r/\sW`*\_L9?P630PF(r.//!lm1c&=Bo0>j$JR-u5,$<!L[^_HZa+B=3smtdR[EZ/thjhm-"Y=`m$]AmThnC[:+>oDLY,/)tml`!BseuOG;mn%#j7%bGPHp"Y!/ff`48V\Uu![(OW$SA]5bD-9r=kIP1$W[4:?1jIYJ>J"7a/l<P6FJh_DXL(cV/.!#?FN]DJU=_LcYXB(IIR3?/]5D02<C*P!:D;V5q-1o<X>eX5O.rhZkgYq*\rc09q]9JSbXm.ccD>l&pi=?JDmaX;Kp+J:o<PQSKrY\'7.Zt*\h'cH?<u@c/>JeO*^_'XQ3#RU7(bkNKQi+:QS\Eks9`@KuTi"j]Bj+&7G5C,?TqA~>
 endstream
 endobj
-38 0 obj
+41 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 37 0 R
+/Contents 40 0 R
 >>
 endobj
-39 0 obj
-<< /Length 1227 /Filter [ /ASCII85Decode /FlateDecode ]
+42 0 obj
+<< /Length 1825 /Filter [ /ASCII85Decode /FlateDecode ]
  >>
 stream
-Gat%#gMZ%0&:O:SkV3*9Y"4D\ZpfOVS)&7s5dt%6eU=*eOj-?2*K&]1J)?B)RA=T@0ao!BMK@aERA8`YI.fOl4jRfG_XGNJ*g/3JOp$8EhYmJ7d?Go-L1!%=A+jm7p3.U'5T)bR=0o-_$LpK9]d@A;$0,F-$3%O3e_HmFDrjI<Xg4*%:XD-5mGCP$el?M.PM9j2mXiIB="DE+(M"gX\&>H+Q_cN:255Q5F7u'36rf&S?AdaaY,LGH:n[76_>Fs5Orkhbi.uGLngO#?.@*I5r]^ie,8,tn`W5Yb53,R9ihHU0:oO5J3%<0F`8ZmsoC#)?1^cl=<cO4mYMh([%J",ok#-**2/Fst:0ou.B+GPbN3EdM2jursPja[)c^lCW.7qOjZ8&"&;)j>mbsVR//?jf3_1L)c,.=4J"'I,HoE;B%9o<-6Z,h@jg(\I]/]nrfICj]i)l(3oBMY9MS!@@Q-OL1G0-"6!Kk&*#ao"-d2dk4:oWo(i"F,mG":O(1Y.O&"cB3Z,K]8AP@pQDV:2'V]gq'Rd?)nbPQ<(.,@<NR'^Q`T,;j%S2^F@j,3!jpVDX<:aQCLIaSJ?U+EWu:Ub[V**[9ha]8e"QP9*p[(D?F'a>k[47b%&JA5?TKg4?K-`+8Y@I@rj;@-XbbWjJhO&QSl:Gcnd0(6tpg@=YRjn==;<RNB";aXc"XN@2tcQgFl?$[0Fi_j&D[$SZFJ^0JT:*GCKeM0D4qUR\j2#R30JJftC^Aq"upIm1e`i(^k%gYu5mI":)G=C?sZ')9UM]DL]0`T+IFi])85@Z-;P,jnuXc8,516$G/9WR'5k#a'#l&M?t<hNo)KBHYl.q\%>f\3*A@dn+Irg0iBg@$HZ''fYH.2;c#rneQ6uOPapaW_0kA9FE*mSUD%gJ@-trD+WHJ:4gs`Me<p:dIs.%&Sh0XrF^E60Sp/O"-nhJGTiVk(S1r]H(P\Q1H<^V44_G#(6/K"G\o/aIHUL`0*<Nd9[5?/k]A;_RC7uSY%q2^c_fcuk42pq:AbeNg#NVW*4W/BsOLXj<@DU2Y0Z,G\>l/8h2Z'H>^7?g1cKd+hh5K4XTj^PkI^gC@C[ph1:^qUNH8;cG=Y;i?p-l'uF-Sf,U>b'?5r+bGgpp`fNq7A0K+'i5dClORCAY$mC>HdsAj*sd:9DHrXfZ]49D?;O:YAeJW[dTa['T<(P>V%%6QEMF[R0GpF_#/OItNndi;Ng3&1I;~>
+Gau`T>Ar7S'Roe[csm-QS4JdRXM]Rc9tRP1\h/23p-;9XX[O"28T'uH^I-2-%M`:9!:(1U0PR*d^N8@(?Jd>PmM9.Fe60]P_]j,XlhJ1)s1'i@?O;dU:j>a/SE8ak`V$;4UB0o4nfQ]rLGJYdDRFEo;D.lEVj8$Upb$dY[a&4r+0/$G5A7Th=fK#1,p-*CIdFeOd\=ZhGqul\PB`A8X5^)tV?oqlX&Kf[l"8fu8QqrOQeBh&>$IQW<@kIm.H?2$7PFd=1!'@]h#.SA6nKYn*'=iZnpDC=GhG]FB+ffB`9U(g!B<X)OF%SuXT8l-kj/^BWJHANGY_',D8K-g\g6R!+JeHal4iHNnTKt'R;R5:g-Pd:>`?DE%<s$@beStHq,>DrD/4E=-Tn'?n&qSRV2COsd3d:h_LX`TbU9L>TSk[i3uMrN=_dp)T[Z^O,gK<?(3rhBjm`YkGnD:VepB8](bnuZ3Ik_1YO/,-80l8@[kY:Q85#d,j+GQo<OL52*IX2HJB%d?ORT^K_F.0=6^=*,Li_SLAZLeYY1_RFH+D@+VB7Blb&j2tC1!n]kFsOP9#AU-=.Pd#qsH`VpANk/')F&kl3>#&A?C_r+HDlTB!]b4:hW6.FtMZ"heuL<9eZCCeoG9shp7jZ;LLis4u`.X*(+`'?V\C?>80A)&W[lb6(oMI:ddTo'Y.jM9Q_@71_SU2P.QOJ=q23B%+b8s\5a=P,+,,6e-V$/r<3<nQ3sg&WPVF'nRN(18@6b;UK?e_X^?R(VcMnYcY"41WMaa4Md@#9iF5*>kP-`)bNf)tok]"\kk+&W#:/"[cSkCb_<ZI<))h_!*-f[C[]<of/FtipIG+VqK"KW8k36cUa\!!h:NeERM^4)/9[?&R8@/O/jZ*Jj&2`8[3#P=SJTEMLGe@=@2cai^cP3I8G/uML\uF4s9o:,!Yd1fDWli/2k5dW0$h\)7b"<uOiUQ0#NJRJ5/&)tm;hkSci:)[<Y\(O$<J"!ie9b^GlTG6Y9XD)mI!2tPG.LY-bT>RI*-:1(h`-]$O0[Ii^]8A[G7"g*.mD;-ri#ekFb%r&GW]Xm"JHrSj?d7dj)Pb=>.aAdO,%MRDO$#c+>ab&,GE/bg._?-8<0pg&e9,UTpR=jHE!)UCb8"_<*un]>i?gb8he:M$?)WIF0s*m/eKogaYf=1PuU5nV-'IE/Q"Ag)QpOO,%I-jJG[j7%7.C$RC:7`l<p\P![L2k)k!M;f.cg\0Jh74!geSK;QBd%>l`I8261YHB5\-Jl[@GVD3j+r4cI`Wd;H_Cd^UMu2W:\oet)L5iWr^Tk<:5IC,Nm9gj/7q]%S38?)`3.(Q`+@K3icn/QOs^\e1RHrm]6=F[FChE2B@CF@%5"Ag=fMgBfH_FGt)2/$up_^Rg?4_\mF'4M<SM$tmV&:o1GgDE>'O,k]=J;V+h6jWL+,5^D)MH4`;Q<kb*rL+sa$_+0[WoLe->,i[V9cf?S_#KH-',t;gjB0V1$kQ7;kF*`QN:^TX!$2f9++YXMEnS`^%:X*leWDA,[oS_QmB]Pe1&=iJ1@d3i0ha2#?FfjYM^P,e0leZg-CPW6&mn8.sf+8:"\8>kGLZ9iP+YRS_'X#\t'Bm,-0F.)l-4p5tVC\_n0FrG?0)&6$1[!bMWgXoAkADeQ<&Nq+f'UpS@Ff7d_e[$B!,C^gR,MX1$sd0sFI<Vb(3'rk8&p(FCLrn@d'flW,6@Fm"^I]JGU`iQI,T`t]W`V1DtWOt8Cs=u)?f2Y#9k:(2e&p/G,&QfWX!GPFk_moor<>&"e']I(RF-$[j4MG-I2;B@(Sg:<N>&Z8k93B^Y?]Um/~>
 endstream
 endobj
-40 0 obj
+43 0 obj
 << /Type /Page
 /Parent 1 0 R
 /MediaBox [ 0 0 612 792 ]
 /Resources 3 0 R
-/Contents 39 0 R
+/Contents 42 0 R
 >>
 endobj
-42 0 obj
+44 0 obj
+<< /Length 605 /Filter [ /ASCII85Decode /FlateDecode ]
+ >>
+stream
+Gat$t9okbt&A@ZcHqY%9g'2&^Sso)&e@i4mDOV[Q)$hgP=_$1R^TT?p6WT)O66JKKcgs8;AsW^GC%*$;<8.'i8-gOjNaqsGpoqKk+c_ZhF9m<u]8oF2\u1?>q]dZoi^h!O'TGL%@k&^f^7aZ6Sh[rJ5>h:%P*25T-;Ym67SG.`cKBHO5+Za6XlHI"Mf+oG\]ObIKB[O=ENY>[d=0QqOEIdd00jkte.pM-#Y^%ZlVP12=e"M#^^$]b"14_@?<>Jj]R.;FU:YG!c6=em:Fqa%-l;!&66)PK(0@Z>cKr$4k;;g:RaE3]6h)m\=H(on@;c'M1FQeB;c\RJ6+L`h<jgg]LL6,^O8BEI*k;X%k2s5>)j;;B\h\2Q^[60E3p?&aM]lfHA>(KI`9Iq*ck'-AN4O2`V+51IE0dmg&MZYB#;E#ib15@4ag;q>q7+-W3m+:@dk_Da.ki7N$U0Q1:!AC7.K&73LuVN8-ps6O((c\<mo]stCiXMU8uB_JP)4uJk)XPCPF*R4fk]%+W3<4LdoC[672F<o5NC6<Am<r`oE64_EW,7oP:Ff69J:SWXX2$3<3!bB>$ZL5Ed%m"*U#_,`4gEp!MS0Z0`~>
+endstream
+endobj
+45 0 obj
+<< /Type /Page
+/Parent 1 0 R
+/MediaBox [ 0 0 612 792 ]
+/Resources 3 0 R
+/Contents 44 0 R
+>>
+endobj
+47 0 obj
 <<
  /Title (\376\377\0\61\0\40\0\120\0\162\0\157\0\147\0\162\0\141\0\155\0\155\0\151\0\156\0\147\0\40\0\167\0\151\0\164\0\150\0\40\0\102\0\157\0\157\0\153\0\113\0\145\0\145\0\160\0\145\0\162)
- /Parent 41 0 R
- /First 43 0 R
- /Last 48 0 R
- /Count -6
+ /Parent 46 0 R
+ /First 48 0 R
+ /Last 54 0 R
+ /Count -7
  /A 9 0 R
 >> endobj
-43 0 obj
+48 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\61\0\40\0\111\0\156\0\163\0\164\0\141\0\156\0\164\0\151\0\141\0\164\0\151\0\156\0\147\0\40\0\102\0\157\0\157\0\153\0\113\0\145\0\145\0\160\0\145\0\162\0\56)
- /Parent 42 0 R
- /Next 44 0 R
+ /Parent 47 0 R
+ /Next 49 0 R
  /A 11 0 R
 >> endobj
-44 0 obj
+49 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\62\0\40\0\103\0\162\0\145\0\141\0\164\0\151\0\156\0\147\0\40\0\141\0\40\0\154\0\145\0\144\0\147\0\145\0\162\0\56)
- /Parent 42 0 R
- /Prev 43 0 R
- /Next 45 0 R
+ /Parent 47 0 R
+ /Prev 48 0 R
+ /Next 50 0 R
  /A 13 0 R
 >> endobj
-45 0 obj
+50 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\63\0\40\0\101\0\144\0\144\0\151\0\156\0\147\0\40\0\145\0\156\0\164\0\162\0\151\0\145\0\163\0\40\0\164\0\157\0\40\0\141\0\40\0\154\0\145\0\144\0\147\0\145\0\162\0\56)
- /Parent 42 0 R
- /Prev 44 0 R
- /Next 46 0 R
+ /Parent 47 0 R
+ /Prev 49 0 R
+ /Next 51 0 R
  /A 15 0 R
 >> endobj
-46 0 obj
+51 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\64\0\40\0\103\0\154\0\157\0\163\0\151\0\156\0\147\0\40\0\141\0\40\0\154\0\145\0\144\0\147\0\145\0\162\0\56)
- /Parent 42 0 R
- /Prev 45 0 R
- /Next 47 0 R
+ /Parent 47 0 R
+ /Prev 50 0 R
+ /Next 52 0 R
  /A 17 0 R
 >> endobj
-47 0 obj
+52 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\65\0\40\0\117\0\160\0\145\0\156\0\151\0\156\0\147\0\40\0\141\0\40\0\154\0\145\0\144\0\147\0\145\0\162\0\56)
- /Parent 42 0 R
- /Prev 46 0 R
- /Next 48 0 R
+ /Parent 47 0 R
+ /Prev 51 0 R
+ /Next 53 0 R
  /A 19 0 R
 >> endobj
-48 0 obj
+53 0 obj
 <<
  /Title (\376\377\0\61\0\56\0\66\0\40\0\122\0\145\0\141\0\144\0\151\0\156\0\147\0\40\0\146\0\162\0\157\0\155\0\40\0\154\0\145\0\144\0\147\0\145\0\162)
- /Parent 42 0 R
- /Prev 47 0 R
+ /Parent 47 0 R
+ /Prev 52 0 R
+ /Next 54 0 R
  /A 21 0 R
 >> endobj
-49 0 obj
+54 0 obj
+<<
+ /Title (\376\377\0\61\0\56\0\67\0\40\0\104\0\145\0\154\0\145\0\164\0\151\0\156\0\147\0\40\0\141\0\40\0\154\0\145\0\144\0\147\0\145\0\162)
+ /Parent 47 0 R
+ /Prev 53 0 R
+ /A 23 0 R
+>> endobj
+55 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F3
 /BaseFont /Helvetica-Bold
 /Encoding /WinAnsiEncoding >>
 endobj
-50 0 obj
+56 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F5
 /BaseFont /Times-Roman
 /Encoding /WinAnsiEncoding >>
 endobj
-51 0 obj
+57 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F1
 /BaseFont /Helvetica
 /Encoding /WinAnsiEncoding >>
 endobj
-52 0 obj
+58 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F9
 /BaseFont /Courier
 /Encoding /WinAnsiEncoding >>
 endobj
-53 0 obj
+59 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F2
 /BaseFont /Helvetica-Oblique
 /Encoding /WinAnsiEncoding >>
 endobj
-54 0 obj
+60 0 obj
 << /Type /Font
 /Subtype /Type1
 /Name /F7
@@ -361,131 +406,143 @@ endobj
 endobj
 1 0 obj
 << /Type /Pages
-/Count 7
-/Kids [6 0 R 23 0 R 32 0 R 34 0 R 36 0 R 38 0 R 40 0 R ] >>
+/Count 8
+/Kids [6 0 R 25 0 R 35 0 R 37 0 R 39 0 R 41 0 R 43 0 R 45 0 R ] >>
 endobj
 2 0 obj
 << /Type /Catalog
 /Pages 1 0 R
- /Outlines 41 0 R
+ /Outlines 46 0 R
  /PageMode /UseOutlines
  >>
 endobj
 3 0 obj
 << 
-/Font << /F3 49 0 R /F5 50 0 R /F1 51 0 R /F9 52 0 R /F2 53 0 R /F7 54 0 R >> 
+/Font << /F3 55 0 R /F5 56 0 R /F1 57 0 R /F9 58 0 R /F2 59 0 R /F7 60 0 R >> 
 /ProcSet [ /PDF /ImageC /Text ] >> 
 endobj
 9 0 obj
 <<
 /S /GoTo
-/D [23 0 R /XYZ 85.0 659.0 null]
+/D [25 0 R /XYZ 85.0 659.0 null]
 >>
 endobj
 11 0 obj
 <<
 /S /GoTo
-/D [23 0 R /XYZ 85.0 518.666 null]
+/D [25 0 R /XYZ 85.0 501.466 null]
 >>
 endobj
 13 0 obj
 <<
 /S /GoTo
-/D [32 0 R /XYZ 85.0 659.0 null]
+/D [35 0 R /XYZ 85.0 653.0 null]
 >>
 endobj
 15 0 obj
 <<
 /S /GoTo
-/D [34 0 R /XYZ 85.0 588.2 null]
+/D [37 0 R /XYZ 85.0 588.2 null]
 >>
 endobj
 17 0 obj
 <<
 /S /GoTo
-/D [36 0 R /XYZ 85.0 622.6 null]
+/D [39 0 R /XYZ 85.0 622.6 null]
 >>
 endobj
 19 0 obj
 <<
 /S /GoTo
-/D [36 0 R /XYZ 85.0 264.947 null]
+/D [39 0 R /XYZ 85.0 264.947 null]
 >>
 endobj
 21 0 obj
 <<
 /S /GoTo
-/D [38 0 R /XYZ 85.0 362.6 null]
+/D [41 0 R /XYZ 85.0 362.6 null]
 >>
 endobj
-41 0 obj
+23 0 obj
+<<
+/S /GoTo
+/D [43 0 R /XYZ 85.0 441.4 null]
+>>
+endobj
+46 0 obj
 <<
- /First 42 0 R
- /Last 42 0 R
+ /First 47 0 R
+ /Last 47 0 R
 >> endobj
 xref
-0 55
+0 61
 0000000000 65535 f 
-0000016858 00000 n 
-0000016958 00000 n 
-0000017050 00000 n 
+0000018885 00000 n 
+0000018992 00000 n 
+0000019084 00000 n 
 0000000015 00000 n 
 0000000071 00000 n 
-0000000808 00000 n 
-0000000928 00000 n 
-0000000995 00000 n 
-0000017184 00000 n 
-0000001130 00000 n 
-0000017247 00000 n 
-0000001267 00000 n 
-0000017313 00000 n 
-0000001404 00000 n 
-0000017377 00000 n 
-0000001541 00000 n 
-0000017441 00000 n 
-0000001677 00000 n 
-0000017505 00000 n 
-0000001814 00000 n 
-0000017571 00000 n 
-0000001951 00000 n 
-0000003859 00000 n 
-0000003982 00000 n 
-0000004044 00000 n 
-0000004181 00000 n 
-0000004318 00000 n 
-0000004455 00000 n 
-0000004591 00000 n 
-0000004728 00000 n 
-0000004865 00000 n 
-0000006896 00000 n 
-0000007004 00000 n 
-0000009019 00000 n 
-0000009127 00000 n 
-0000010911 00000 n 
-0000011019 00000 n 
-0000012995 00000 n 
-0000013103 00000 n 
-0000014423 00000 n 
-0000017635 00000 n 
-0000014531 00000 n 
-0000014808 00000 n 
-0000015058 00000 n 
-0000015279 00000 n 
-0000015552 00000 n 
-0000015767 00000 n 
-0000015982 00000 n 
-0000016196 00000 n 
-0000016309 00000 n 
-0000016419 00000 n 
-0000016527 00000 n 
-0000016633 00000 n 
-0000016749 00000 n 
+0000000838 00000 n 
+0000000958 00000 n 
+0000001032 00000 n 
+0000019218 00000 n 
+0000001167 00000 n 
+0000019281 00000 n 
+0000001304 00000 n 
+0000019347 00000 n 
+0000001441 00000 n 
+0000019411 00000 n 
+0000001578 00000 n 
+0000019475 00000 n 
+0000001714 00000 n 
+0000019539 00000 n 
+0000001851 00000 n 
+0000019605 00000 n 
+0000001988 00000 n 
+0000019669 00000 n 
+0000002125 00000 n 
+0000004120 00000 n 
+0000004243 00000 n 
+0000004312 00000 n 
+0000004449 00000 n 
+0000004586 00000 n 
+0000004723 00000 n 
+0000004859 00000 n 
+0000004996 00000 n 
+0000005133 00000 n 
+0000005270 00000 n 
+0000007304 00000 n 
+0000007412 00000 n 
+0000009427 00000 n 
+0000009535 00000 n 
+0000011319 00000 n 
+0000011427 00000 n 
+0000013403 00000 n 
+0000013511 00000 n 
+0000015429 00000 n 
+0000015537 00000 n 
+0000016234 00000 n 
+0000019733 00000 n 
+0000016342 00000 n 
+0000016619 00000 n 
+0000016869 00000 n 
+0000017090 00000 n 
+0000017363 00000 n 
+0000017578 00000 n 
+0000017793 00000 n 
+0000018021 00000 n 
+0000018223 00000 n 
+0000018336 00000 n 
+0000018446 00000 n 
+0000018554 00000 n 
+0000018660 00000 n 
+0000018776 00000 n 
 trailer
 <<
-/Size 55
+/Size 61
 /Root 2 0 R
 /Info 4 0 R
 >>
 startxref
-17686
+19784
 %%EOF

+ 7 - 3
docs/bookkeeperStarted.html

@@ -272,13 +272,17 @@ document.write("Last Published: " + document.lastModified);
 		</p>
 <p>
 <span class="codefrag computeroutput">
-		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar\
-		-Dlog4j.configuration=log4j.properties org.apache.bookkeeper.proto.BookieServer 3181 /path_to_log_device/\
+		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\
+		:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\ 
+		org.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\
 		/path_to_ledger_device/
 		</span>
 </p>
 <p> "/path_to_log_device/" and "/path_to_ledger_device/" are different paths. Also, port 3181
-		is the port that a bookie listens on for connection requests from clients. 
+		is the port that a bookie listens on for connection requests from clients. 127.0.0.1:2181 is the hostname:port 
+		for the ZooKeeper server. In this example, the standalone ZooKeeper server is running locally on port 2181.
+		If we had multiple ZooKeeper servers, this parameter would be a comma separated list of all the hostname:port
+		values corresponding to them.
 		</p>
 <a name="N10051"></a><a name="bk_setupZK"></a>
 <h3 class="h4">Setting up ZooKeeper</h3>

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 3 - 3
docs/bookkeeperStarted.pdf


+ 8 - 4
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/bookie/Bookie.java

@@ -63,7 +63,6 @@ public class Bookie extends Thread {
     
     // ZK registration path for this bookie
     static final String BOOKIE_REGISTRATION_PATH = "/ledgers/available/";
-    static final String LEDGERS_PATH = "/ledgers";
 
     // ZooKeeper client instance for the Bookie
     ZooKeeper zk;
@@ -136,7 +135,7 @@ public class Bookie extends Thread {
         instantiateZookeeperClient(port, zkServers);
         this.journalDirectory = journalDirectory;
         this.ledgerDirectories = ledgerDirectories;
-        entryLogger = new EntryLogger(ledgerDirectories);
+        entryLogger = new EntryLogger(ledgerDirectories, this);
         ledgerCache = new LedgerCache(ledgerDirectories);
         lastLogMark.readLog();
         final long markedLogId = lastLogMark.txnLogId;
@@ -206,7 +205,9 @@ public class Bookie extends Thread {
         syncThread.start();
     }
 
-    // Method to instantiate the ZooKeeper client for the Bookie.
+    /**
+     * Instantiate the ZooKeeper client for the Bookie.
+     */
     private void instantiateZookeeperClient(int port, String zkServers) throws IOException {
         if (zkServers == null) {
             LOG.warn("No ZK servers passed to Bookie constructor so BookKeeper clients won't know about this server!");
@@ -441,7 +442,8 @@ public class Bookie extends Thread {
     }
 
     public void shutdown() throws InterruptedException {
-    	if(zk != null) zk.close();
+        // Shutdown the ZK client
+        if(zk != null) zk.close();
         this.interrupt();
         this.join();
         syncThread.running = false;
@@ -449,6 +451,8 @@ public class Bookie extends Thread {
         for(LedgerDescriptor d: ledgers.values()) {
             d.close();
         }
+        // Shutdown the EntryLogger which has the GarbageCollector Thread running
+        entryLogger.shutdown();
     }
     
     public void addEntry(ByteBuffer entry, WriteCallback cb, Object ctx, byte[] masterKey)

+ 11 - 0
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/bookie/BufferedChannel.java

@@ -80,6 +80,17 @@ public class BufferedChannel
         return position;
     }
     
+    /**
+     * Retrieve the current size of the underlying FileChannel
+     * 
+     * @return FileChannel size measured in bytes
+     * 
+     * @throws IOException if some I/O error occurs reading the FileChannel
+     */
+    public long size() throws IOException {
+        return bc.size();
+    }
+    
     public void flush(boolean sync) throws IOException {
         synchronized(this) {
             if (writeBuffer == null) {

+ 237 - 14
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/bookie/EntryLogger.java

@@ -35,10 +35,15 @@ import java.nio.ByteBuffer;
 import java.nio.channels.FileChannel;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.log4j.Logger;
+import org.apache.zookeeper.AsyncCallback;
+import org.apache.zookeeper.KeeperException;
+import org.apache.zookeeper.KeeperException.Code;
 
 /**
  * This class manages the writing of the bookkeeper entries. All the new
@@ -50,31 +55,53 @@ import org.apache.log4j.Logger;
 public class EntryLogger {
     private static final Logger LOG = Logger.getLogger(EntryLogger.class);
     private File dirs[];
+    // This is a handle to the Bookie parent instance. We need this to get
+    // access to the LedgerCache as well as the ZooKeeper client handle.
+    private final Bookie bookie;
+
     private long logId;
     /**
      * The maximum size of a entry logger file.
      */
-    final static long LOG_SIZE_LIMIT = 2*1024*1024*1024L;
+    final static long LOG_SIZE_LIMIT = Long.getLong("logSizeLimit", 2 * 1024 * 1024 * 1024L);
     private volatile BufferedChannel logChannel;
-    // The ledgers contained in this file, seems to be unsused right now
-    //private HashSet<Long> ledgerMembers = new HashSet<Long>();
     /**
      * The 1K block at the head of the entry logger file
      * that contains the fingerprint and (future) meta-data
      */
-    final static ByteBuffer LOGFILE_HEADER = ByteBuffer.allocate(1024);
-    static {
-        LOGFILE_HEADER.put("BKLO".getBytes());
-    }
+    final static int LOGFILE_HEADER_SIZE = 1024;
+    final ByteBuffer LOGFILE_HEADER = ByteBuffer.allocate(LOGFILE_HEADER_SIZE);
+
     // this indicates that a write has happened since the last flush
     private volatile boolean somethingWritten = false;
-    
+
+    // ZK ledgers related String constants
+    static final String LEDGERS_PATH = "/ledgers";
+    static final String LEDGER_NODE_PREFIX = "L";
+    static final String AVAILABLE_NODE = "available";
+
+    // Maps entry log files to the set of ledgers that comprise the file.
+    private ConcurrentMap<Long, ConcurrentHashMap<Long, Boolean>> entryLogs2LedgersMap = new ConcurrentHashMap<Long, ConcurrentHashMap<Long, Boolean>>();
+    // This is the thread that garbage collects the entry logs that do not
+    // contain any active ledgers in them.
+    GarbageCollectorThread gcThread = new GarbageCollectorThread();
+    // This is how often we want to run the Garbage Collector Thread (in milliseconds). 
+    // This should be passed as a System property. Default it to 1000 ms (1sec).
+    final static int gcWaitTime = Integer.getInteger("gcWaitTime", 1000);
+
     /**
      * Create an EntryLogger that stores it's log files in the given
      * directories
      */
-    public EntryLogger(File dirs[]) throws IOException {
+    public EntryLogger(File dirs[], Bookie bookie) throws IOException {
         this.dirs = dirs;
+        this.bookie = bookie;
+        // Initialize the entry log header buffer. This cannot be a static object
+        // since in our unit tests, we run multiple Bookies and thus EntryLoggers
+        // within the same JVM. All of these Bookie instances access this header
+        // so there can be race conditions when entry logs are rolled over and
+        // this header buffer is cleared before writing it into the new logChannel.
+        LOGFILE_HEADER.put("BKLO".getBytes());
         // Find the largest logId
         for(File f: dirs) {
             long lastLogId = getLastLogId(f);
@@ -83,14 +110,132 @@ public class EntryLogger {
             }
         }
         createLogId(logId);
-        //syncThread = new SyncThread();
-        //syncThread.start();
+        // Start the Garbage Collector thread to prune unneeded entry logs.
+        gcThread.start();
     }
     
     /**
      * Maps entry log files to open channels.
      */
     private ConcurrentHashMap<Long, BufferedChannel> channels = new ConcurrentHashMap<Long, BufferedChannel>();
+
+    /**
+     * This is the garbage collector thread that runs in the background to
+     * remove any entry log files that no longer contains any active ledger.
+     */
+    class GarbageCollectorThread extends Thread {
+        volatile boolean running = true;
+
+        public GarbageCollectorThread() {
+            super("GarbageCollectorThread");
+        }
+
+        @Override
+        public void run() {
+            while (running) {
+                synchronized (this) {
+                    try {
+                        wait(gcWaitTime);
+                    } catch (InterruptedException e) {
+                        Thread.currentThread().interrupt();
+                        continue;
+                    }
+                }
+                // Initialization check. No need to run any logic if we are still starting up.
+                if (entryLogs2LedgersMap.isEmpty() || bookie.ledgerCache == null
+                        || bookie.ledgerCache.activeLedgers == null) {
+                    continue;
+                }
+                // First sync ZK to make sure we're reading the latest active/available ledger nodes.
+                bookie.zk.sync(LEDGERS_PATH, new AsyncCallback.VoidCallback() {
+                    @Override
+                    public void processResult(int rc, String path, Object ctx) {
+                        if (rc != Code.OK.intValue()) {
+                            LOG.error("ZK error syncing the ledgers node when getting children: ", KeeperException
+                                    .create(KeeperException.Code.get(rc), path));
+                            return;
+                        }
+                        // Sync has completed successfully so now we can poll ZK 
+                        // and read in the latest set of active ledger nodes.
+                        List<String> ledgerNodes;
+                        try {
+                            ledgerNodes = bookie.zk.getChildren(LEDGERS_PATH, null);
+                        } catch (Exception e) {
+                            LOG.error("Error polling ZK for the available ledger nodes: ", e);
+                            // We should probably wait a certain amount of time before retrying in case of temporary issues.
+                            return;
+                        }
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("Retrieved current set of ledger nodes: " + ledgerNodes);
+                        }
+                        // Convert the ZK retrieved ledger nodes to a HashSet for easier comparisons.
+                        HashSet<Long> allActiveLedgers = new HashSet<Long>(ledgerNodes.size(), 1.0f);
+                        for (String ledgerNode : ledgerNodes) {
+                            try {
+                                // The available node is also stored in this path so ignore that.
+                                // That node is the path for the set of available Bookie Servers.
+                                if (ledgerNode.equals(AVAILABLE_NODE))
+                                    continue;
+                                String parts[] = ledgerNode.split(LEDGER_NODE_PREFIX);
+                                allActiveLedgers.add(Long.parseLong(parts[parts.length - 1]));
+                            } catch (NumberFormatException e) {
+                                LOG.fatal("Error extracting ledgerId from ZK ledger node: " + ledgerNode);
+                                // This is a pretty bad error as it indicates a ledger node in ZK
+                                // has an incorrect format. For now just continue and consider
+                                // this as a non-existent ledger.
+                                continue;
+                            }
+                        }
+                        ConcurrentMap<Long, Boolean> curActiveLedgers = bookie.ledgerCache.activeLedgers;
+                        if (LOG.isDebugEnabled()) {
+                            LOG.debug("All active ledgers from ZK: " + allActiveLedgers);
+                            LOG.debug("Current active ledgers from Bookie: " + curActiveLedgers.keySet());
+                        }
+                        // Remove any active ledgers that don't exist in ZK.
+                        for (Long ledger : curActiveLedgers.keySet()) {
+                            if (!allActiveLedgers.contains(ledger)) {
+                                // Remove it from the current active ledgers set and also from all 
+                                // LedgerCache data references to the ledger, i.e. the physical ledger index file.
+                                LOG.info("Removing a non-active/deleted ledger: " + ledger);
+                                curActiveLedgers.remove(ledger);
+                                try {
+                                    bookie.ledgerCache.deleteLedger(ledger);
+                                } catch (IOException e) {
+                                    LOG.error("Exception when deleting the ledger index file on the Bookie: ", e);
+                                }
+                            }
+                        }
+                        // Loop through all of the entry logs and remove the non-active ledgers.
+                        for (Long entryLogId : entryLogs2LedgersMap.keySet()) {
+                            ConcurrentHashMap<Long, Boolean> entryLogLedgers = entryLogs2LedgersMap.get(entryLogId);
+                            for (Long entryLogLedger : entryLogLedgers.keySet()) {
+                                // Remove the entry log ledger from the set if it isn't active.
+                                if (!bookie.ledgerCache.activeLedgers.containsKey(entryLogLedger)) {
+                                    entryLogLedgers.remove(entryLogLedger);
+                                }
+                            }
+                            if (entryLogLedgers.isEmpty()) {
+                                // This means the entry log is not associated with any active ledgers anymore.
+                                // We can remove this entry log file now.
+                                LOG.info("Deleting entryLogId " + entryLogId + " as it has no active ledgers!");
+                                File entryLogFile;
+                                try {
+                                    entryLogFile = findFile(entryLogId);
+                                } catch (FileNotFoundException e) {
+                                    LOG.error("Trying to delete an entryLog file that could not be found: "
+                                            + entryLogId + ".log");
+                                    continue;
+                                }
+                                entryLogFile.delete();
+                                channels.remove(entryLogId);
+                                entryLogs2LedgersMap.remove(entryLogId);
+                            }
+                        }
+                    };
+                }, null);
+            }
+        }
+    }
     
     /**
      * Creates a new log file with the given id.
@@ -108,6 +253,9 @@ public class EntryLogger {
         for(File f: dirs) {
             setLastLogId(f, logId);
         }
+        // Extract all of the ledger ID's that comprise all of the entry logs
+        // (except for the current new one which is still being written to).
+        extractLedgersFromEntryLogs();
     }
 
     /**
@@ -228,6 +376,9 @@ public class EntryLogger {
         }
         File file = findFile(entryLogId);
         FileChannel newFc = new RandomAccessFile(file, "rw").getChannel();
+        // If the file already exists before creating a BufferedChannel layer above it,
+        // set the FileChannel's position to the end so the write buffer knows where to start.
+        newFc.position(newFc.size());
         synchronized (channels) {
             fc = channels.get(entryLogId);
             if (fc != null){
@@ -250,9 +401,6 @@ public class EntryLogger {
         throw new FileNotFoundException("No file for log " + Long.toHexString(logId));
     }
     
-    public void close() {
-    }
-
     synchronized public boolean testAndClearSomethingWritten() {
         try {
             return somethingWritten;
@@ -261,4 +409,79 @@ public class EntryLogger {
         }
     }
 
+    /**
+     * Method to read in all of the entry logs (those that we haven't done so yet),
+     * and find the set of ledger ID's that make up each entry log file.
+     */
+    private void extractLedgersFromEntryLogs() throws IOException {
+        // Extract it for every entry log except for the current one.
+        // Entry Log ID's are just a long value that starts at 0 and increments
+        // by 1 when the log fills up and we roll to a new one.
+        ByteBuffer sizeBuff = ByteBuffer.allocate(4);
+        BufferedChannel bc;
+        for (long entryLogId = 0; entryLogId < logId; entryLogId++) {
+            // Comb the current entry log file if it has not already been extracted.
+            if (entryLogs2LedgersMap.containsKey(entryLogId)) {
+                continue;
+            }
+            LOG.info("Extracting the ledgers from entryLogId: " + entryLogId);
+            // Get the BufferedChannel for the current entry log file
+            try {
+                bc = getChannelForLogId(entryLogId);
+            } catch (FileNotFoundException e) {
+                // If we can't find the entry log file, just log a warning message and continue.
+                // This could be a deleted/garbage collected entry log.
+                LOG.warn("Entry Log file not found in log directories: " + entryLogId + ".log");
+                continue;
+            }
+            // Start the read position in the current entry log file to be after
+            // the header where all of the ledger entries are.
+            long pos = LOGFILE_HEADER_SIZE;
+            ConcurrentHashMap<Long, Boolean> entryLogLedgers = new ConcurrentHashMap<Long, Boolean>();
+            // Read through the entry log file and extract the ledger ID's.
+            while (true) {
+                // Check if we've finished reading the entry log file.
+                if (pos >= bc.size()) {
+                    break;
+                }
+                if (bc.read(sizeBuff, pos) != sizeBuff.capacity()) {
+                    throw new IOException("Short read from entrylog " + entryLogId);
+                }
+                pos += 4;
+                sizeBuff.flip();
+                int entrySize = sizeBuff.getInt();
+                if (entrySize > 1024 * 1024) {
+                    LOG.error("Sanity check failed for entry size of " + entrySize + " at location " + pos + " in "
+                            + entryLogId);
+                }
+                byte data[] = new byte[entrySize];
+                ByteBuffer buff = ByteBuffer.wrap(data);
+                int rc = bc.read(buff, pos);
+                if (rc != data.length) {
+                    throw new IOException("Short read for entryLog " + entryLogId + "@" + pos + "(" + rc + "!="
+                            + data.length + ")");
+                }
+                buff.flip();
+                long ledgerId = buff.getLong();
+                entryLogLedgers.put(ledgerId, true);
+                // Advance position to the next entry and clear sizeBuff.
+                pos += entrySize;
+                sizeBuff.clear();
+            }
+            LOG.info("Retrieved all ledgers that comprise entryLogId: " + entryLogId + ", values: " + entryLogLedgers);
+            entryLogs2LedgersMap.put(entryLogId, entryLogLedgers);
+        }
+    }
+
+    /**
+     * Shutdown method to gracefully stop all threads spawned in this class and exit.
+     * 
+     * @throws InterruptedException if there is an exception stopping threads.
+     */
+    public void shutdown() throws InterruptedException {
+        gcThread.running = false;
+        gcThread.interrupt();
+        gcThread.join();
+    }
+
 }

+ 11 - 0
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/bookie/FileInfo.java

@@ -33,6 +33,7 @@ import java.nio.channels.FileChannel;
  */
 class FileInfo {
     private FileChannel fc;
+    private final File lf;
     /**
      * The fingerprint of a ledger index file
      */
@@ -42,6 +43,7 @@ class FileInfo {
     private int useCount;
     private boolean isClosed;
     public FileInfo(File lf) throws IOException {
+        this.lf = lf;
         fc = new RandomAccessFile(lf, "rws").getChannel();
         size = fc.size();
         if (size == 0) {
@@ -110,4 +112,13 @@ class FileInfo {
             }
         }
     }
+    
+    /**
+     * Getter to a handle on the actual ledger index file.
+     * This is used when we are deleting a ledger and want to physically remove the index file.
+     */
+    File getFile() {
+        return lf;
+    }
+
 }

+ 82 - 0
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/bookie/LedgerCache.java

@@ -33,6 +33,8 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Random;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.log4j.Logger;
 
@@ -48,6 +50,8 @@ public class LedgerCache {
 
     public LedgerCache(File ledgerDirectories[]) {
         this.ledgerDirectories = ledgerDirectories;
+        // Retrieve all of the active ledgers.
+        getActiveLedgers();
     }
     /**
      * the list of potentially clean ledgers
@@ -63,6 +67,9 @@ public class LedgerCache {
     
     LinkedList<Long> openLedgers = new LinkedList<Long>();
     
+    // Stores the set of active (non-deleted) ledgers.
+    ConcurrentMap<Long, Boolean> activeLedgers = new ConcurrentHashMap<Long, Boolean>();
+
     static int OPEN_FILE_LIMIT = 900;
     static {
         if (System.getProperty("openFileLimit") != null) {
@@ -208,6 +215,12 @@ public class LedgerCache {
                     File dir = pickDirs(ledgerDirectories);
                     lf = new File(dir, ledgerName);
                     checkParents(lf);
+                    // A new ledger index file has been created for this Bookie.
+                    // Add this new ledger to the set of active ledgers.
+                    if (LOG.isDebugEnabled()) {
+                        LOG.debug("New ledger index file created for ledgerId: " + ledger);
+                    }
+                    activeLedgers.put(ledger, true);
                 }
                 if (openLedgers.size() > OPEN_FILE_LIMIT) {
                     fileInfoCache.remove(openLedgers.removeFirst()).close();
@@ -451,4 +464,73 @@ public class LedgerCache {
         
         return lastEntry;
     }
+
+    /**
+     * This method will look within the ledger directories for the ledger index
+     * files. That will comprise the set of active ledgers this particular
+     * BookieServer knows about that have not yet been deleted by the BookKeeper
+     * Client. This is called only once during initialization.
+     */
+    private void getActiveLedgers() {
+        // Ledger index files are stored in a file hierarchy with a parent and
+        // grandParent directory. We'll have to go two levels deep into these
+        // directories to find the index files.
+        for (File ledgerDirectory : ledgerDirectories) {
+            for (File grandParent : ledgerDirectory.listFiles()) {
+                if (grandParent.isDirectory()) {
+                    for (File parent : grandParent.listFiles()) {
+                        if (parent.isDirectory()) {
+                            for (File index : parent.listFiles()) {
+                                if (!index.isFile() || !index.getName().endsWith(".idx")) {
+                                    continue;
+                                }
+                                // We've found a ledger index file. The file name is the 
+                                // HexString representation of the ledgerId.
+                                String ledgerIdInHex = index.getName().substring(0, index.getName().length() - 4);
+                                activeLedgers.put(Long.parseLong(ledgerIdInHex, 16), true);
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Active ledgers found: " + activeLedgers);
+        }
+    }
+    
+    /**
+     * This method is called whenever a ledger is deleted by the BookKeeper Client
+     * and we want to remove all relevant data for it stored in the LedgerCache.
+     */
+    void deleteLedger(long ledgerId) throws IOException {
+        if (LOG.isDebugEnabled())
+            LOG.debug("Deleting ledgerId: " + ledgerId);
+        // Delete the ledger's index file and close the FileInfo
+        FileInfo fi = getFileInfo(ledgerId, false);
+        fi.getFile().delete();
+        fi.close();
+
+        // Remove it from the activeLedgers set
+        activeLedgers.remove(ledgerId);
+
+        // Now remove it from all the other lists and maps. 
+        // These data structures need to be synchronized first before removing entries. 
+        synchronized(this) {
+            pages.remove(ledgerId);
+        }
+        synchronized(fileInfoCache) {
+            fileInfoCache.remove(ledgerId);
+        }
+        synchronized(cleanLedgers) {
+            cleanLedgers.remove(ledgerId);
+        }
+        synchronized(dirtyLedgers) {
+            dirtyLedgers.remove(ledgerId);
+        }
+        synchronized(openLedgers) {
+            openLedgers.remove(ledgerId);
+        }
+    }
+
 }

+ 13 - 0
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/client/AsyncCallback.java

@@ -98,4 +98,17 @@ public interface AsyncCallback {
     void readComplete(int rc, LedgerHandle lh, Enumeration<LedgerEntry> seq,
         Object ctx);
   }
+  
+  public interface DeleteCallback {
+      /**
+       * Callback definition for delete operations
+       * 
+       * @param rc
+       *          return code
+       * @param ctx
+       *          control object
+       */
+      void deleteComplete(int rc, Object ctx);
+    }
+
 }

+ 57 - 8
src/contrib/bookkeeper/src/java/org/apache/bookkeeper/client/BookKeeper.java

@@ -23,19 +23,18 @@ package org.apache.bookkeeper.client;
 
 import java.io.IOException;
 import java.util.concurrent.Executors;
-import org.apache.bookkeeper.client.BKException;
+
 import org.apache.bookkeeper.client.AsyncCallback.CreateCallback;
+import org.apache.bookkeeper.client.AsyncCallback.DeleteCallback;
 import org.apache.bookkeeper.client.AsyncCallback.OpenCallback;
 import org.apache.bookkeeper.client.BKException.Code;
-import org.apache.bookkeeper.client.SyncCounter;
 import org.apache.bookkeeper.proto.BookieClient;
 import org.apache.bookkeeper.util.OrderedSafeExecutor;
 import org.apache.log4j.Logger;
-
-import org.apache.zookeeper.Watcher;
-import org.apache.zookeeper.ZooKeeper;
 import org.apache.zookeeper.KeeperException;
 import org.apache.zookeeper.WatchedEvent;
+import org.apache.zookeeper.Watcher;
+import org.apache.zookeeper.ZooKeeper;
 import org.jboss.netty.channel.socket.ClientSocketChannelFactory;
 import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
 
@@ -43,8 +42,8 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
  * BookKeeper client. We assume there is one single writer to a ledger at any
  * time.
  * 
- * There are three possible operations: start a new ledger, write to a ledger,
- * and read from a ledger.
+ * There are four possible operations: start a new ledger, write to a ledger,
+ * read from a ledger and delete a ledger.
  * 
  * The exceptions resulting from synchronous calls and error code resulting from
  * asynchronous calls can be found in the class {@link BKException}.
@@ -52,7 +51,7 @@ import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
  * 
  */
 
-public class BookKeeper implements OpenCallback, CreateCallback {
+public class BookKeeper implements OpenCallback, CreateCallback, DeleteCallback {
 
   static final Logger LOG = Logger.getLogger(BookKeeper.class);
 
@@ -333,6 +332,56 @@ public class BookKeeper implements OpenCallback, CreateCallback {
     return counter.getLh();
   }
 
+  /**
+   * Deletes a ledger asynchronously.
+   * 
+   * @param lId
+   *            ledger Id
+   * @param cb
+   *            deleteCallback implementation
+   * @param ctx
+   *            optional control object
+   */
+  public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) {
+      new LedgerDeleteOp(this, lId, cb, ctx).initiate();
+  }
+  
+  /**
+   * Delete callback implementation for synchronous delete call.
+   * 
+   * @param rc
+   *            return code
+   * @param ctx
+   *            optional control object
+   */
+  public void deleteComplete(int rc, Object ctx) {
+      SyncCounter counter = (SyncCounter) ctx;
+      counter.setrc(rc);
+      counter.dec();
+  }
+
+  /**
+   * Synchronous call to delete a ledger. Parameters match those of
+   * {@link #asyncDeleteLedger(long, DeleteCallback, Object)}
+   * 
+   * @param lId
+   *            ledgerId
+   * @throws InterruptedException
+   * @throws BKException
+   */
+  public void deleteLedger(long lId) throws InterruptedException, BKException {
+      SyncCounter counter = new SyncCounter();
+      counter.inc();
+      // Call asynchronous version
+      asyncDeleteLedger(lId, this, counter);
+      // Wait
+      counter.block(0);
+      if (counter.getrc() != KeeperException.Code.OK.intValue()) { 
+          LOG.error("ZooKeeper error deleting ledger node: " + counter.getrc());
+          throw BKException.create(Code.ZKException);
+      }
+  }
+  
   /**
    * Shuts down client.
    * 

+ 1 - 1
src/contrib/bookkeeper/test/org/apache/bookkeeper/test/CloseTest.java

@@ -33,7 +33,7 @@ import org.apache.log4j.Logger;
  */
 
 public class CloseTest extends BaseTestCase{
-    static Logger LOG = Logger.getLogger(LedgerRecoveryTest.class);
+    static Logger LOG = Logger.getLogger(CloseTest.class);
     DigestType digestType;
 
     public CloseTest(DigestType digestType) {

+ 10 - 3
src/docs/src/documentation/content/xdocs/bookkeeperConfig.xml

@@ -100,8 +100,9 @@
  	   </para>
  	   
  	   <para><computeroutput>
-		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar\
-		-Dlog4j.configuration=log4j.properties org.apache.bookkeeper.proto.BookieServer 3181 /path_to_log_device/\
+		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\
+		:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\ 
+		org.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\
 		/path_to_ledger_device/
 	   </computeroutput></para>
  	   
@@ -116,6 +117,12 @@
  	   	</para>
  	   	</listitem>
  	   	
+ 	   	<listitem>
+ 	   	<para>
+ 	   		Comma separated list of ZooKeeper servers with a hostname:port format;
+ 	   	</para>
+ 	   	</listitem>
+ 	   	
  	   	<listitem>
  	   	<para>
  	   		Path for Log Device (stores bookie write-ahead log);
@@ -146,4 +153,4 @@
  	   </para>
  	 </section>
   </section>
-</article>
+</article>

+ 70 - 0
src/docs/src/documentation/content/xdocs/bookkeeperProgrammer.xml

@@ -69,6 +69,10 @@
         <para><xref linkend="bk_readLedger" /></para>
       </listitem>
       
+      <listitem>
+        <para><xref linkend="bk_deleteLedger" /></para>
+      </listitem>
+      
     </itemizedlist>
     
     <section id="bk_instance">
@@ -604,5 +608,71 @@
 		</listitem>
 	</itemizedlist>	
     </section>
+
+    <section id="bk_deleteLedger">
+    <title> Deleting a ledger </title>
+    <para>
+    Once a client is done with a ledger and is sure that nobody will ever need to read from it again, they can delete the ledger.
+    The following methods belong to <computeroutput>org.apache.bookkeeper.client.BookKeeper</computeroutput>.
+    </para>
+    
+    <para>
+   	<emphasis role="bold">Synchronous delete:</emphasis>
+   	</para>
+    
+    <para>
+    <computeroutput>
+        public void deleteLedger(long lId) throws InterruptedException, BKException
+    </computeroutput>
+    </para>
+
+	<itemizedlist>
+	<listitem>
+	<para>
+	<computeroutput>lId</computeroutput> is the ledger identifier;
+	</para>
+	</listitem>
+	</itemizedlist>
+    
+    <para>
+   	<emphasis role="bold">Asynchronous delete:</emphasis>
+    </para>
+    <para>
+      <computeroutput>
+	 public void asyncDeleteLedger(long lId, DeleteCallback cb, Object ctx) 
+      </computeroutput>
+    </para>
+	
+    <para>
+    It takes a ledger identifier. Additionally, it takes a callback object 
+    <computeroutput>cb</computeroutput> and a control object <computeroutput>ctx</computeroutput>. The callback object must implement
+    the <computeroutput>DeleteCallback</computeroutput> interface in <computeroutput>org.apache.bookkeeper.client.AsyncCallback</computeroutput>, and
+	a class implementing it has to implement a method called <computeroutput>deleteComplete</computeroutput>
+	that has the following signature: 
+    </para>
+
+	<para>
+	<computeroutput>
+	void deleteComplete(int rc, Object ctx)
+	</computeroutput>    
+	</para>
+	
+	<para>
+	where:
+	</para>
+	<itemizedlist>
+		<listitem>
+		<para>
+		<computeroutput>rc</computeroutput> is a return code (please refer to <computeroutput>org.apache.bookeeper.client.BKDefs</computeroutput> for a list);
+		</para>
+		</listitem>
+	
+		<listitem>
+		<para>
+		<computeroutput>ctx</computeroutput> is control object used for accountability purposes. 
+		</para>
+		</listitem>
+	</itemizedlist>	
+    </section>
    </section>
 </article>

+ 8 - 4
src/docs/src/documentation/content/xdocs/bookkeeperStarted.xml

@@ -87,13 +87,17 @@
 		</para>
 		
 		<para><computeroutput>
-		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar\
-		-Dlog4j.configuration=log4j.properties org.apache.bookkeeper.proto.BookieServer 3181 /path_to_log_device/\
+		java -cp .:./zookeeper-&lt;version&gt;-bookkeeper.jar:./zookeeper-&lt;version&gt;.jar\
+		:../log4j/apache-log4j-1.2.15/log4j-1.2.15.jar -Dlog4j.configuration=log4j.properties\ 
+		org.apache.bookkeeper.proto.BookieServer 3181 127.0.0.1:2181 /path_to_log_device/\
 		/path_to_ledger_device/
 		</computeroutput></para>
 		
 		<para> "/path_to_log_device/" and "/path_to_ledger_device/" are different paths. Also, port 3181
-		is the port that a bookie listens on for connection requests from clients. 
+		is the port that a bookie listens on for connection requests from clients. 127.0.0.1:2181 is the hostname:port 
+		for the ZooKeeper server. In this example, the standalone ZooKeeper server is running locally on port 2181.
+		If we had multiple ZooKeeper servers, this parameter would be a comma separated list of all the hostname:port
+		values corresponding to them.
 		</para>
 	  </section>
 	  
@@ -201,4 +205,4 @@ lh.close();
 	    </programlisting>
 	  </section>  
   </section>
-</article>
+</article>

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio