diff --git a/pkg/btree/multi_test.go b/pkg/btree/multi_test.go index 4695f39d..048c6e98 100644 --- a/pkg/btree/multi_test.go +++ b/pkg/btree/multi_test.go @@ -7,6 +7,16 @@ import ( "github.com/kevmo314/appendable/pkg/buftest" ) +/* +func writeBufferToFile(bytes []byte, filename string) error { + if err := os.WriteFile(filename, bytes, 0644); err != nil { + return err + } + return nil +} + +*/ + func TestMultiBPTree(t *testing.T) { t.Run("empty tree", func(t *testing.T) { b := buftest.NewSeekableBuffer() @@ -135,6 +145,9 @@ func TestMultiBPTree(t *testing.T) { t.Fatal(err) } metadata, err := tree.Metadata() + + // writeBufferToFile(metadata, "empty_metadata.bin") + if err != nil { t.Fatal(err) } @@ -160,6 +173,9 @@ func TestMultiBPTree(t *testing.T) { t.Fatal(err) } metadata, err := tree.Metadata() + + // writeBufferToFile(metadata, "filled_metadata.bin") + if err != nil { t.Fatal(err) } diff --git a/pkg/btree/node.go b/pkg/btree/node.go index 4737b562..65f1c90e 100644 --- a/pkg/btree/node.go +++ b/pkg/btree/node.go @@ -133,7 +133,7 @@ func (n *BPTreeNode) UnmarshalBinary(buf []byte) error { n.Keys[i].DataPointer.Offset = binary.BigEndian.Uint64(buf[m+4 : m+12]) n.Keys[i].DataPointer.Length = binary.BigEndian.Uint32(buf[m+12 : m+16]) dp := n.Keys[i].DataPointer - n.Keys[i].Value = n.Data[dp.Offset : dp.Offset+uint64(dp.Length)] + n.Keys[i].Value = n.Data[dp.Offset : dp.Offset+uint64(dp.Length)] // resolving the data-file m += 4 + 12 } else { n.Keys[i].Value = buf[m+4 : m+4+int(l)] diff --git a/src/btree/bptree.ts b/src/btree/bptree.ts index 1d4571ce..460ec244 100644 --- a/src/btree/bptree.ts +++ b/src/btree/bptree.ts @@ -18,7 +18,7 @@ type RootResponse = { export class BPTree { private readonly tree: RangeResolver; private meta: MetaPage; - private readonly data: Uint8Array; + private readonly data: Uint8Array; // RangeResolver for the data-file constructor(tree: RangeResolver, meta: MetaPage, data: Uint8Array) { this.tree = tree; diff --git a/src/btree/multi.ts b/src/btree/multi.ts index 66ddf6a8..79d0eaf9 100644 --- a/src/btree/multi.ts +++ b/src/btree/multi.ts @@ -31,23 +31,31 @@ export class LinkedMetaPage { }; } + /** + * `metadata()` gets the page data. It does the following: + * (1) creates a slice from 24 to the end of the page + * (2) it reads the first four bytes of that slice which gives us the length to seek to + * (3) slices from [24, (24 + dataLength)] which contain metadata + */ async metadata(): Promise { + console.log("metadata entered"); const pageData = await this.getMetaPage(); + console.log("page data: ", pageData) const lengthData = pageData.slice( - Number(this.offset) + 24, - Number(this.offset) + PAGE_SIZE_BYTES - 1 + 24, + PAGE_SIZE_BYTES ); const lengthView = new DataView(lengthData); - // read the first four because that represnts length + // read the first four because that represents length const metadataLength = lengthView.getUint32(0); - const metadata = pageData.slice( - Number(this.offset) + 28, - Number(this.offset) + metadataLength - 1 - ); - return metadata; + console.log("metadatalength: ", metadataLength); + return pageData.slice( + 28, + 28 + metadataLength + ); } private async getMetaPage(): Promise { @@ -60,6 +68,7 @@ export class LinkedMetaPage { end: Number(this.offset) + PAGE_SIZE_BYTES - 1, }); + this.metaPageData= data; return data; diff --git a/src/tests/filled_metadata.bin b/src/tests/filled_metadata.bin new file mode 100644 index 00000000..b6fc4c62 --- /dev/null +++ b/src/tests/filled_metadata.bin @@ -0,0 +1 @@ +hello \ No newline at end of file diff --git a/src/tests/multi.test.ts b/src/tests/multi.test.ts index fa78c401..71013c32 100644 --- a/src/tests/multi.test.ts +++ b/src/tests/multi.test.ts @@ -1,18 +1,51 @@ -import {RangeResolver} from "../resolver"; +import {LengthIntegrityError, RangeResolver} from "../resolver"; import {PageFile} from "../btree/pagefile"; import {ReadMultiBPTree} from "../btree/multi"; +import {arrayBufferToString, readBinaryFile} from "./test-util"; + + describe("test multi", () => { - let resolver: RangeResolver; + let mockRangeResolver: RangeResolver; + + beforeEach(async () => { + + mockRangeResolver = async({ start, end, expectedLength }) => { + const bufferSize = 4096 * 2; // 2 blocks of 4kb each + const buffer = new ArrayBuffer(bufferSize); + const view = new Uint8Array(buffer); + + const metadata = new Uint8Array(await readBinaryFile("filled_metadata.bin")); + const metadataLength = metadata.byteLength; + + const dataView = new DataView(buffer); + dataView.setUint32(4096 + 24, metadataLength); + + view.set(metadata, 4096 + 24 + 4); + const slice = view.slice(start, end + 1); + + if(expectedLength !== undefined && slice.byteLength !== expectedLength) { + throw new LengthIntegrityError; + } + + return { + data: slice.buffer, + totalLength: view.byteLength, + } + } + }) + it("storing metadata works", async() => { - // const pageFile = new PageFile(resolver); - // - // const tree = ReadMultiBPTree(resolver, pageFile); - // - // const metadata = await tree.metadata(); - // console.log(metadata); + + + + const pageFile = new PageFile(mockRangeResolver); + const tree = ReadMultiBPTree(mockRangeResolver, pageFile); + const metadata = await tree.metadata(); + + expect("hello").toEqual(arrayBufferToString(metadata)) }); }); diff --git a/src/tests/node.test.ts b/src/tests/node.test.ts index d903112d..901ed111 100644 --- a/src/tests/node.test.ts +++ b/src/tests/node.test.ts @@ -1,8 +1,7 @@ import { ReferencedValue } from "../btree/bptree"; import { BPTreeNode, MemoryPointer } from "../btree/node"; -import fs from 'fs/promises'; -import path from 'path'; import {RangeResolver} from "../resolver"; +import {readBinaryFile} from "./test-util"; const strToArrayBuffer = (str: string) => { return new Uint8Array(str.split("").map((c) => c.charCodeAt(0))).buffer; @@ -44,12 +43,6 @@ describe("test compare bytes", () => { }); -const readBinaryFile = async (filename: string): Promise => { - const filePath = path.join(__dirname, filename); - const data = await fs.readFile(filePath); - return new Uint8Array(data); -}; - describe("node functionality", () => { let resolver: RangeResolver; diff --git a/src/tests/test-util.ts b/src/tests/test-util.ts new file mode 100644 index 00000000..fdc5f9c9 --- /dev/null +++ b/src/tests/test-util.ts @@ -0,0 +1,15 @@ +import path from "path"; +import fs from "fs/promises"; + +export async function readBinaryFile(filename: string): Promise { + const filePath = path.join(__dirname, filename); + const data = await fs.readFile(filePath); + return new Uint8Array(data); +}; + +export function arrayBufferToString(arrayBuffer: ArrayBuffer): string { + const decoder = new TextDecoder("utf-8"); + const uint8Array = new Uint8Array(arrayBuffer); + + return decoder.decode(uint8Array) +}