From 3f5ed8ae880d3b228f33b7f546c93275a7d3d1c3 Mon Sep 17 00:00:00 2001 From: Joe Date: Thu, 21 Mar 2024 10:48:23 -0700 Subject: [PATCH] refactoring LightBlockUpload and writing tests --- src/server.ts | 2 +- src/upload/index.test.ts | 88 +++++++++++------------------ src/upload/index.ts | 66 +++++++++++++--------- test/cache/leveldb/000116.ldb | Bin 0 -> 7677 bytes test/cache/leveldb/000120.ldb | Bin 0 -> 1766 bytes test/cache/leveldb/000123.log | Bin 0 -> 2407 bytes test/cache/leveldb/CURRENT | 2 +- test/cache/leveldb/LOG | 3 + test/cache/leveldb/LOG.old | 8 ++- test/cache/leveldb/MANIFEST-000122 | Bin 0 -> 189 bytes 10 files changed, 83 insertions(+), 86 deletions(-) create mode 100644 test/cache/leveldb/000116.ldb create mode 100644 test/cache/leveldb/000120.ldb create mode 100644 test/cache/leveldb/000123.log create mode 100644 test/cache/leveldb/MANIFEST-000122 diff --git a/src/server.ts b/src/server.ts index 8593954..df80937 100644 --- a/src/server.ts +++ b/src/server.ts @@ -17,7 +17,7 @@ if (process.env["BUILD_CACHE"] === "true") { if (process.env["UPLOAD_BLOCKS"] === "true") { logger.info("Starting uploader..."); - void lightBlockUpload.watchAndUpload(); + void lightBlockUpload.upload(); } export const app = express(); diff --git a/src/upload/index.test.ts b/src/upload/index.test.ts index 5e8b707..795b261 100644 --- a/src/upload/index.test.ts +++ b/src/upload/index.test.ts @@ -1,70 +1,50 @@ -import { LightBlockUpload } from "./index"; +import { lightBlockCache } from "../cache"; +import { lightBlockUpload } from "./index"; import { - S3Client, PutObjectCommand, ListObjectsV2Command, + S3Client, } from "@aws-sdk/client-s3"; -import { LightBlockCache } from "../cache"; -import { LightBlock } from "../models/lightstreamer"; - -jest.mock("@aws-sdk/client-s3", () => { - return { - S3Client: jest.fn().mockImplementation(() => { - return { - send: jest.fn().mockImplementation(() => { - return { Contents: [] }; - }), - }; - }), - ListObjectsV2Command: jest.fn().mockImplementation(() => { - return {}; - }), - PutObjectCommand: jest.fn().mockImplementation(() => { - return {}; - }), - }; -}); describe("LightBlockUpload", () => { - let lightBlockUpload: LightBlockUpload; - let mockCache: jest.Mocked; - let mockS3Client: jest.Mocked; - beforeAll(() => { - mockCache = new LightBlockCache() as jest.Mocked; - mockS3Client = new S3Client({}) as jest.Mocked; - lightBlockUpload = new LightBlockUpload(mockCache); + jest.spyOn(S3Client.prototype, "send").mockImplementation((command) => { + if (command instanceof ListObjectsV2Command) { + return Promise.resolve({ + Contents: [ + { Key: lightBlockUpload.uploadName({ start: 1, end: 1000 }) }, + { Key: lightBlockUpload.uploadName({ start: 1001, end: 2000 }) }, + ], + }); + } else if (command instanceof PutObjectCommand) { + return Promise.resolve({ + /* your mock PutObjectCommand response */ + }); + } else { + throw new Error( + `Command mock not implemented: ${command.constructor.name}`, + ); + } + }); }); - afterAll(() => { + afterAll(async () => { jest.resetAllMocks(); + await lightBlockCache.close(); }); - it("should throw an error if environment variables are not set", () => { - delete process.env["BUCKET_ENDPOINT"]; - expect(() => new LightBlockUpload(mockCache)).toThrow(); + it("upload name creation should be reversible", () => { + const blockRange = { start: 1, end: 1000 }; + const key = lightBlockUpload.uploadName(blockRange); + const newBlockRange = lightBlockUpload.parseUploadName(key); + expect(blockRange).toEqual(newBlockRange); }); - it("should upload blocks", async () => { - const mockBlock = LightBlock.fromJSON({ - sequence: 1000, - hash: "test-hash", - previousBlockHash: "test-previous-hash", - timestamp: 123456789, - transactions: [], - noteSize: 0, - }); - mockCache.getBlockBySequence.mockResolvedValue(mockBlock); - mockCache.getHeadSequence.mockResolvedValue(1001); - mockCache.getUploadHead.mockResolvedValue(0); - - const mockSend = jest.fn(); - mockS3Client.send = mockSend; - - await lightBlockUpload.watchAndUpload(); - - expect(mockSend).toHaveBeenCalledWith(expect.any(ListObjectsV2Command)); - expect(mockSend).toHaveBeenCalledWith(expect.any(PutObjectCommand)); - expect(mockCache.putUploadHead).toHaveBeenCalledWith("test-hash"); + it("existing uploads should return block ranges", async () => { + const ranges = await lightBlockUpload.existingUploads(); + expect(ranges).toEqual([ + { start: 1, end: 1000 }, + { start: 1001, end: 2000 }, + ]); }); }); diff --git a/src/upload/index.ts b/src/upload/index.ts index f49a6cb..980bdcf 100644 --- a/src/upload/index.ts +++ b/src/upload/index.ts @@ -8,7 +8,7 @@ import { LightBlockCache, lightBlockCache } from "@/cache"; import { LightBlock } from "@/models/lightstreamer"; import { logger } from "@/utils/logger"; -class UploaderError extends Error {} +class UploadError extends Error {} type BlockRange = { start: number; @@ -23,16 +23,16 @@ export class LightBlockUpload { constructor(cache: LightBlockCache) { this.cache = cache; if (!process.env["BUCKET_ENDPOINT"]) { - throw new UploaderError("BUCKET_ENDPOINT not set"); + throw new UploadError("BUCKET_ENDPOINT not set"); } if (!process.env["BUCKET_ACCESS_KEY_ID"]) { - throw new UploaderError("BUCKET_ACCESS_KEY_ID not set"); + throw new UploadError("BUCKET_ACCESS_KEY_ID not set"); } if (!process.env["BUCKET_SECRET_ACCESS_KEY"]) { - throw new UploaderError("BUCKET_SECRET_ACCESS_KEY not set"); + throw new UploadError("BUCKET_SECRET_ACCESS_KEY not set"); } if (!process.env["BUCKET_NAME"]) { - throw new UploaderError("BUCKET_NAME not set"); + throw new UploadError("BUCKET_NAME not set"); } this.bucket = process.env["BUCKET_NAME"]; this.s3Client = new S3Client({ @@ -45,16 +45,17 @@ export class LightBlockUpload { }); } - async watchAndUpload(): Promise { + async upload(): Promise { // eslint-disable-next-line no-constant-condition while (true) { - const blocks = await this.blocksToUpload(); + const existingUploads = await this.existingUploads(); + const blocks = await this.uploadManifest(existingUploads); for (const block of blocks) { logger.info(`Gzipping blocks ${block.start} to ${block.end}`); const gzip = await this.gzipBlocks(block.start, block.end); logger.info(`Uploading blocks ${block.start} to ${block.end}`); - const key = this.uploadName(block.start, block.end); + const key = this.uploadName(block); await this.uploadBlocks(gzip, key); const uploadHead = await this.cache.getBlockBySequence(block.end); if (uploadHead) { @@ -65,7 +66,7 @@ export class LightBlockUpload { } } - private async gzipBlocks(start: number, end: number): Promise { + async gzipBlocks(start: number, end: number): Promise { let data = ""; for (let i = start; i <= end; i++) { const block = await this.cache.getBlockBySequence(i); @@ -74,11 +75,10 @@ export class LightBlockUpload { Buffer.from(LightBlock.encode(block).finish()).toString("hex") + "\n"; } } - return gzipSync(data); } - private async uploadBlocks(buffer: Buffer, key: string): Promise { + async uploadBlocks(buffer: Buffer, key: string): Promise { const command = new PutObjectCommand({ Bucket: this.bucket, ContentType: "application/gzip", @@ -90,33 +90,45 @@ export class LightBlockUpload { await this.s3Client.send(command); } - private uploadName(start: number, end: number): string { - return `blocks_${start.toString().padStart(10, "0")}_${end + async existingUploads(): Promise { + const { Contents } = await this.s3Client.send( + new ListObjectsV2Command({ Bucket: this.bucket }), + ); + + if (!Contents) return []; + const keys = Contents.map((item) => item.Key).filter(Boolean) as string[]; + return keys.map((key) => { + return this.parseUploadName(key); + }); + } + + uploadName(range: BlockRange): string { + return `blocks_${range.start.toString().padStart(10, "0")}_${range.end .toString() .padStart(10, "0")}.gz`; } - private async blocksToUpload(): Promise { + parseUploadName(uploadName: string): BlockRange { + const match = uploadName.match(/blocks_(\d+)_(\d+)\.gz/); + if (match) { + return { start: parseInt(match[1], 10), end: parseInt(match[2], 10) }; + } + throw new UploadError("Invalid upload name: " + uploadName); + } + + async uploadManifest(existingUploads: BlockRange[]): Promise { const head = await this.cache.getHeadSequence(); if (!head) return []; const headBlockSequence = parseInt(head.toString()); - - const { Contents } = await this.s3Client.send( - new ListObjectsV2Command({ Bucket: this.bucket }), - ); - - if (!Contents) return []; - const keys = Contents.map((item) => item.Key).filter(Boolean) as string[]; const backfillBlocks = []; - for (let i = 0; i <= headBlockSequence; i += 1000) { - if (headBlockSequence - i < 1000) { + for (let start = 1; start <= headBlockSequence; start += 1000) { + if (headBlockSequence - start < 1000) { continue; } - const end = Math.min(i + 999, headBlockSequence); - const key = this.uploadName(i, end); - if (!keys.includes(key)) { - backfillBlocks.push({ start: i, end }); + const end = Math.min(start + 999, headBlockSequence); + if (!existingUploads.includes({ start, end })) { + backfillBlocks.push({ start, end }); } } return backfillBlocks; diff --git a/test/cache/leveldb/000116.ldb b/test/cache/leveldb/000116.ldb new file mode 100644 index 0000000000000000000000000000000000000000..fd24aaf328202bcd1611edbcfcc4744a4159af94 GIT binary patch literal 7677 zcmbtYcUV))w%?ls$PNJ_5PA!UQZ>B*0s*85$e{`->Q0l6Qbp+^Qp5s^qN0M*K?NI# z(p6NzLKh1bKmnCzK}FxrIro0weSf_B?sw08SyR?pdonY>nKf(8h&CQ@Xh)GiaK?hn zqjGs92Ajg7FnDa3!l0A+3;~@-VN-cD9+g6(aQRd!na2|F$P5ad&SH~kWRj4|BT+$B z006}nPJ$Q^52V=bf7yNZ6t~;$hHS>7 zyI}CTh4WZ%RxoF#Tl!v^@71lu*b*J|5udl6G`nlR*VzpRRje5bkqk-eIBaI!xX<1% zV~}Z4RN>^D%TDlRokid^ZCygwAesQ_wnezuuKgzMGJKB@H7Ax&Ily-ikxU-j4Cp9zjrb%<^^^435 zZ0m!v-x%`fbo>v8gS(oCY+pHdeW$MvE!$eR%l=HTO|aF2FXtLw>o@0+%Y7z04-IEM zi5a++*fdwYBhoadY^P&Hc$l_bU}S)HSa_5`TM)*Jh}#|&h%iF~!vqo9!Gbu_KN9gx zDhSNju%yIo+EEmk$KncM293mH^C>(&1*Qo|JhFgC;R~1~9+gI8l3*^G%;d4DLN1jg zgatGfk4<5ch2S!P197l`1P8lt02Hgv{?5l08b3Kd+B$7Afuq@DYnARB|7j@|8?g-k-ju!*n7A(_xAB|-(3FM z&7J{)Lz|p}oAx=rx-=}fgKPW?X@BM}yP@a^w{(R}bkoI=nBMGeqDEeSh*8+dtr`{R zx~g1$z^{-(W@Ei;|3G{2C6mG4YFA1zQArbisj;9P!jk@jzmd7A`K+afw4BwvQEhj6 zlIhjR{3gi*iWagi#;A9PuPlFXWY3&jdVQ1pjoqiQkpGqFyZz6j_1_)4W;a_Rwy)(> zxn;8EqW(#V%PknQ+R1k)&jFwG{_U|kvsM#YPG8x7>|_VkYzvyq!98e?x&+Q+JwROx zGkEOt4`-538KYxgLNR=r+7K)0c0;Qa`}76N`rfP8#}D4QUv`2RFvA8T#@6qw9n4y-(szh2EbN`?OWPqR-?&JuRpnxAVwa7b-^4`!k@ z$#vWRg76ns3|V1hm1oRpY!+1j3wR_Ri%o+W0s)CirV8k67%{U95|7WMQOQDzfGiX; z7(yP8!h&fq6Q;9R3<{{^g#{3_0d&Mq@jt=9=)W9u!|wDw{+jGmI5a9Crf(4zBGR@=uD)yAIx4SaPVlm2oPg zbGofi<(~SAR9lB2N&Mj^p-ig~-}UVTvzCuv_5*s*)y?UzpMdvM8X!qLncv4Y7` zGzv#0OkUwgE49xwNBoJ$U52FU!HCyfHz<9nO26{TVYzr5yzJzB+T%oB{{6tB!$+n} zG*oe(DHd(_k}H{4^X)e|VrQ1_7km%<=^cX-@1833`|#_>hK2?4VE5X@_u-Dg6BR4o z`D7B(UhJcPkeo1PT-x{ilkRd?J*E@xl?qA}z=bBHVBmy(=GZ z9Z7~RXYvwB-FGQx0wYjM(5j75gycGWlF5{jZSry4Nv+B0I>(0%0pfX#{qB{agQ;&` zD<-Eu`>-|XqvUhTW5mc=S|QE6m+I~%4+ERC%gvNfr$N0MGWPQoySEef)t+~aUl}v3 z=6xIde!?;37&qt6KQP0J`C|dZPR*EesWd8uMkccv0y33MW7BwKDwR*8!Yn?C&Zp3+ zJSLSvVv=E&kVz3x5KBlVu~`fuALfGM2x^G&jClth($S79xRc!Y*#E>xWbSC&uK3Ek zWBD(ScoqH*^t^fT{sCc%*Jrv@ z)lkWh@Vmz?LYD4y21lJT2CnF_JLj;=Tt^|R?)D=M;m*r9@UvS#p2BtxD~lVNnNnRa z*KFC#$He0`dRE6|mA}**K3}n?JIXfh^pw20)3a;m>~G073Lh&B#w}I{8aB<3?N@R; zlOofec~Wa36ZgSWTIJ_1g}#LG=imHSB)axaBsy^JGgs&38YwL8vD8=j_r zNCC69vlj2qxNg?S9us4GdUxz!WeeRdk+8}A9i-t>ZKOy%uH#M%C7MB)DSTCPd>N}cM+r5TaH`}v&J*MpNj5wv~xyJ3w zm#jY)Ozu*9Uz94}OScPPwKp6vOVKFp3~9aS|JGo1i*?dX#awz{npOMx+M$|6|H6aP z(FNQ^YktD_-%X{(Pggx|t^brAb}4MtRGpuscl8Z--4ov(aL@-y&2z^hl*AHG73A^F zr>mCAt{Eg@#8k+!oBIui#_~W=%Az?B9?K#W239W(+1-D6^+dv>FHYR@ZaTcJ_+o4Pzd)lc0U!w!(XDBjTf-|BUW0$eZistNrgJF_#AOgU z5oDf_#iDTq6tmqewLNPHnEBkC6bkkCzB z6uSL;cU|Pr|9fclOFI7P(3|9D%R8wy8qNEMzg;mG?N$A%@-V)T^+Ez8ldgRqNB_$k zgll@okn&D&^U#OJ6byjpq9?~LY@cumJOih<1SPIAA0eS3kOn%d)AzpbSX zeC6#``e^-cqnRVxjnwv?`~b{G#hr;xVirr^30F?MR?S!ZcKPoGrpB zHvizuEb-gsjmGQtNo=NQ_cT67&Da8ucNQMBElV-3IfdFqIqh3Jd~M{15K-O8#Hi{(qqx z@nt>;sIw#i$chZ2^m=CO04AHw<}p|#E|*WH^Vu+;%cQa?Nccu!!b~0v^O%V5$lwd; zBIl9J60jLm2Axk5@);~LjU=FgkQE8kgq+2bXY6R~|K6>U7H6=TR3_+!Y)Nf5XNj9U(C&}}vG2M(JbO|MSvHu>v#uD||a#9kY( z_;xBg5wBOVuhzTb(r(Ig#uxr!&~L|w%mmLL#=VXLgV4<;QwmlSjmixsF)O9vgoXnW zwJFu1xZ|H@@s#1&(A+!y#skt-7X!jrCn^=%;-2?qOr`sH-PZlsg+Xg}Sn^np@8m2D ze!#SZXoqfm(|~GOyfZyU8|V3CNqjkezYe(uWn?vb<~Dxuibip zbUZjv=NsdD)FtkfjWXkVN$8JrV|kHPp+36j@X<%Yy2~#~es@ju6r=51QQlxbiZ(xk z&+L6Tkh;C|N8M+K-!1W`Yd)rp6&l&kd~8Q1GbpKPc*rXDqEou+CKy&wY~-C$gnC4DaXq_Aaa zIB``)`0A0*>to z(0ik_?Tgi_#rcvm_k_P0m->}UXB@7MUr{G9SJY$tWrAD(RN^qA7z(>-1Ww@>-D57hzoKCj@h-S&hp$C z+XZP2{IlanyNB0P-(O73qJ9`wDvfJhoV=dj5_{K~?H2dIDY6k&9#9{WbXU}l*Q)5_9v>Tct$20h%G7#=|6@_dqrn-+d=v(G?mJgw7(HFH z2bXPkcWK?RXwse2>xJHPU51~(DSrC4Xt`5IM^3wz`y#fc+D!G)%NwyHBmCep$;D$q z+&k3Ot9Gw`KP$D#pkToRByyg--)0uzSe1bHe`O_gDX{4EHlTUMQZdfq^iBz5>>t~E zo?TO#S5KQb&vv01R-N(Qy~k%GTkc+i3VFlAam$OXQd@4sDzEtwoV%p6x6L-RYlp+W zw4A#$`AhB7_LSnfe1h8A@UNd9n$H$XTrAHhP!Bp#`||G9P>EBM{R0|iANu#!#%mqj zn-y?C3?Hf$5%dRhZd(BL+*8)zXKj3#-j2m*rH^V>2k2g9`8+Ivw%3Z2Vw9-Q2_M_` zohmGC4cpL6qT;Q7$hjE4o9^G(ZjY9hP71#ho^fAe-osxtju+#_>RSzr3l z%Hy`2DD-^huti?iknQ!jQGT2xSzlu#Zo?GDQ87QzFTeUjl3cRIm)Y}{oR$J?WZxtz zy4(LJ*_`eCDSOz?-YSrO*q~bGf*@nY?r%Ic1JW6Ce_l4ACm`;wju^nq3s_Z_xHJg>mVau# zh5Q^>D|$d!98!xXUX=KLLh5)~q$vSO;fYAO4a5Nf5FX97hcE;Q zbC@EdKeYI7Z%R;2|_?H6$aNj6VUZfD}8erN9_q8AySYjhBUR5RN25 zu4G6~nx^fIRAUfQhZF%hND`93vB=O42y3DQNkbBN0wQ8UQh+5Si8c*{FeZthw{*U- zL0~u{FmZ*}-c2Lk12z&2F#dye5Dw!Mq)Ys&|F9I1sv)!^4pPQNDWlB5B_NSFtuGpt zmIjh}JdkGMk&>-N+zf8j)_vBD4hrvY9GVsP6L z1)>n$kxnq;REnlx?SkU0=DZ|YV{|O#I1SR85Jf#`3nJ(}zmp>ntvPPndfz_K9Id7- zeFZGS=-A4EKExi3^rvQVc{E=LIRGkeaC@2A*UcP&Kk_94pzpoKe$8ep(IlDkFk*YqC2CsuOL{%#|*qMiv>l}iSeEev= z(Hb9rI~^zDIt~i(0tW%v&~mT_FeI2O??x0X!|((=y0?J14eb~YCji2@D53_ij-UtF zKv;~)r)B{aZL~c_8*StVDS{f{VQ>_ZL(BOPB_UkOW!%=CtH2aJjAOhx*aUpKS_#@i zD@D5jgHSO19q{5PW zh3kg7fJxwYUliUK>A@K?NFf4l93e3R9Y!R62Erg!1p^D=E`O?YE!t@_tc`Y4=I8-x zpo?g)Jw5;j;d=HfZU8Ab8Ke#00M9B*8up>FkI@_p&ag7VgLeAabJ|jz!En)@h>qii zs)HNhTNp_f0@wx^K*>09;oTYt3tk}VV7SjNa4NMCJy}ECgX{z_TzxIxQr!t*xI`0k zAi9EpCMC2catcHXznfD5DFeH~B`~apgMXI3Y%K*+!^K9`mT|P zP6Rn{RSKQ33|Te-o#TdnRKtk~{RR<@MRRdL$m~;A6(lDDK(Xzd4i=KZJK=+<49)=B zC_s7}pbicJ%B>tUdR^-$-!X_nkO2JQSU|c6Tcir(i&OyDR&$U5FQK`ipbUY6_Ev%8 zVLgoPr)KhFNE4tJr65aPiCK$m=p@nLu+k+Q%&S%fd2FoXN>zv~;;lric0&JYLJHG- z(;5+oHu|D_=g+9u_u8^i0EY<>z&bn literal 0 HcmV?d00001 diff --git a/test/cache/leveldb/000120.ldb b/test/cache/leveldb/000120.ldb new file mode 100644 index 0000000000000000000000000000000000000000..47ec487c50273ab56cb414453b39fd755f22a6e2 GIT binary patch literal 1766 zcmaJ?eN0=|6~8yWHt*Qa@Ob!{7cjxkKmr&DHs&ihflC7f9GWE&1d@>Dk=S5^?LZ8K zCWN@%Sh6O-2CInD3B{^FmBVC0d7$ZyUwVS}P2iGpP_=+f((oLiA{hmV4R?W{ zSc1AgyZrsn|MPB+|1Bo-{bjJ0rQ8Oi*2K_z>on~VdiI8td<9sn1Z<}(7nt=SChS2n zv@@vOIiJcyaWf(i=sk!>IAdNFO~bQs@CP`(|IQ<5TZeeu=W1*YiFS<^UFq(K#1d;@y+Ugu63(bkvT>-?HW4@GnniC?A0@v z>lwS>0gaxZya@`Lij!^OSk(-AM_6;<5dEt-jxygXY}sC{U4!x(3lTkBZlx)b!>{NY zs30Ce2Q9*0TTr}w$;h$2*TgsSe`@W5r&Z=x?CZeqiv19YThAWjVWTPH$o+%2X^<7F z_7}*w7H3;!I-sox_RO+5j~$M{HnJA71W#r;_d$mf1Nyv>PjVm&hx%!vHw(l>i|K^w zwf+D6(zzeNdbaC;_7Rygx<=Y@_Gfsy94c=y>kWp{y_`caG9!8ks^&inLfNby68k>5 zvW6#weT4_0R2)D*I-*azyUi%c8-2xRU1EH=%%^#coI16C@TZ}{<*Kh(Z}GfkndKGI^{lc1oGb+(U~PVUj@ak~$n>tO5rdK?iC#KSzZf)0gQ#wYinK;{@`yIc z5}Ni2NkD<4VoT(Kp*s5?S?GZ7W;<10Mha=KF>g12rpLsUN1S`8U(7~be~CV$W>wy1 z)|-rP;eR)Z1;_Sw@oVYrG-=Gm)a-EFMfd5i2wA-fy+$hFlxU7zzW`QxQS%7Hs~7o_ z8~t)B#Wx?Gqe)kX)anYMp?69<3-yk0z!quO_)|vdkMrk2CCBMKnz+EF)rH&+KNL!N z`3Jj-`4jp!p;}Ag5J$BJAra`&|EKz9uAjE8JYM~h+Bg(y?g;Ltm)OWI;9wcFlXA$_ zRpZv8v`dktyvf@y)@mU|rZwq$B^L`9u6G!7bK?S^jDH4Nm66RhL`&wU=Rr1_;Jo%5 zj}@||kQA$H;D2M@QTqsS(f5gZl{40JH8Xe@{ECGP=`+N>Xk9GOrNy;m$JHQJ^m}YL zPO}w1>tCy%(949anPuNiSV!s?(^%{!p#!IS-uOJL{kKN57Z=p|JnKyNh63;z<_%yi zoqP9JiXrdctX(d>ubkS1uzr{hI#+~XL>~(qzY2nj8t6UWw&0-_Ut7sDCW~POgpK_A z1K;n7#}tW_~GH2_9@h(iT3eiGT!+OM$YLqHC463SXi87+ryP&r*_aMQ&b z^}?8#EE-Q_yIA6)S=7WVA=%7?u|*SzmnPo03$KhfK9BF8AEH;1=Xnp``~UsE@BQBQ z<8OS@eJe+=8H$iU4U{I@H?iomT{r49NjL5ovMQC>$>-mF1GJT<_lgC%s#>a%8Wjb5 zu=3#tmKxQqa5|Ga(o9Sm($LS%rgeJ%2Y{VH@*WvO_OqpAgCxiJpXnGB)qH~C5f zoLI2S1|i@({opk)TZW9HL{{4L^I|D!IT}oZht-jCG!MJZR2==zXNT2D{1(VFyd{5AIj4 z!zkxrMAF#*98%D&3&F5(jq}MTy!EUM0k=Newh#>DwoEVjas$DTC)X30TnNvFrZG4> z9q=sV&UnIS|Ic69-FThGSj~e24sP+hxPbDWnMD~BIg)U2L-m<5n&!KvOl8enpry&Eyg7diE{86AA%NqeEKte{(qZ;l zWta^NL^CvTn1?8aIiWS~kF760dl44UGZqQCCXUEP{_Ya9sW0Bs8g{g>I$1zRF$Kp7 za@o3qFk7kbm#-sPZNsK9NMI1;G%a9TG=#C#W>)ToS$BbrsbZKX%iBYSb?ewB&q)1`%H7&Dx1$ctPV3d?W%V{tP&{Z(K^Tb!8#dm;=msAdiP0kVsLj_tnvI*qqTd#{THeWRaLaUTM2; zv(p~mOdsGI2_QR{PsbKN)f#rSPM9ogK)*cHnhu=}aysB@*bT`V;7TWph(1Nm(40uijIdN@Yv(Ljd?6gV1&pu3J21cAbvTkmuv4sEt literal 0 HcmV?d00001 diff --git a/test/cache/leveldb/CURRENT b/test/cache/leveldb/CURRENT index 61135ee..d9766b1 100644 --- a/test/cache/leveldb/CURRENT +++ b/test/cache/leveldb/CURRENT @@ -1 +1 @@ -MANIFEST-000231 +MANIFEST-000122 diff --git a/test/cache/leveldb/LOG b/test/cache/leveldb/LOG index e69de29..6d8d746 100644 --- a/test/cache/leveldb/LOG +++ b/test/cache/leveldb/LOG @@ -0,0 +1,3 @@ +2024/03/19-09:37:17.297631 173e2b000 Recovering log #121 +2024/03/19-09:37:17.298491 173e2b000 Delete type=3 #119 +2024/03/19-09:37:17.298537 173e2b000 Delete type=0 #121 diff --git a/test/cache/leveldb/LOG.old b/test/cache/leveldb/LOG.old index 9b28481..f8abcef 100644 --- a/test/cache/leveldb/LOG.old +++ b/test/cache/leveldb/LOG.old @@ -1,3 +1,5 @@ -2024/03/20-17:13:07.794174 171fcb000 Recovering log #230 -2024/03/20-17:13:07.795044 171fcb000 Delete type=3 #229 -2024/03/20-17:13:07.795090 171fcb000 Delete type=0 #230 +2024/03/19-09:37:16.985331 172e13000 Recovering log #118 +2024/03/19-09:37:16.985449 172e13000 Level-0 table #120: started +2024/03/19-09:37:16.985657 172e13000 Level-0 table #120: 1766 bytes OK +2024/03/19-09:37:16.986076 172e13000 Delete type=3 #117 +2024/03/19-09:37:16.986118 172e13000 Delete type=0 #118 diff --git a/test/cache/leveldb/MANIFEST-000122 b/test/cache/leveldb/MANIFEST-000122 new file mode 100644 index 0000000000000000000000000000000000000000..e16ab56832903bf2f2bf669fefb5038c000fd462 GIT binary patch literal 189 zcmbOdd%b%(10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei17JPey8D3ZpLr7_c)` zJmcjvG_y1}HfM~0h(Q!YLKQHU{I&Kl00F~f