public static void T01_BlockEncodeDecodeTest() { MemoryStream ms = new MemoryStream(); byte[] testdata = { 0x00, 0x10, 0x78, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00 }; // init an encoder and add one key which requires escaping { ISegmentBlockEncoder enc = new SegmentBlockBasicEncoder(); enc.setStream(ms); RecordKey key = new RecordKey().appendParsedKey("TESTSETEST"); RecordUpdate update = RecordUpdate.WithPayload(testdata); enc.add(key, update); enc.flush(); ms.Flush(); System.Console.WriteLine("Test Update: " + update.ToString()); } byte[] block_contents = ms.ToArray(); System.Console.WriteLine("Block Output: " + BitConverter.ToString(block_contents)); // init the decoder { ISegmentBlockDecoder dec = new SegmentBlockBasicDecoder(new BlockAccessor(ms.ToArray())); foreach (var kvp in dec.sortedWalk()) { System.Console.WriteLine("Payload Update: " + kvp.Value.ToString()); byte[] payload = kvp.Value.data; Assert.AreEqual(testdata, payload, "payload data mismatch!"); } } }
private byte[] fetchLogEntries_block(string log_server_guid, string log_start_key, string log_end_key) { var rk_start = new RecordKey() .appendKeyPart("_logs") .appendKeyPart(log_server_guid) .appendKeyPart(log_start_key); var rk_end = RecordKey.AfterPrefix(new RecordKey() .appendKeyPart("_logs") .appendKeyPart(log_server_guid) .appendKeyPart(log_end_key)); var scanrange = new ScanRange<RecordKey>(rk_start, rk_end, null); byte[] packed_log_records; { MemoryStream writer = new MemoryStream(); // TODO: this seems like a really inefficient way to write out a key ISegmentBlockEncoder encoder = new SegmentBlockBasicEncoder(); encoder.setStream(writer); foreach (var logrow in next_stage.scanForward(scanrange)) { encoder.add(logrow.Key, RecordUpdate.WithPayload(logrow.Value.data)); } encoder.flush(); packed_log_records = writer.ToArray(); } // IF there are no log entries... BLOCK! return packed_log_records; }
public void setValue(RecordKey skey, RecordUpdate supdate) { checkActive(); // (1) write our repl log entry DateTime now = DateTime.Now; long logstamp = id_gen.nextTimestamp(); RecordKey logkey = new RecordKey() .appendKeyPart("_logs") .appendKeyPart(ctx.server_guid) .appendKeyPart(new RecordKeyType_Long(logstamp)); // (1.1) pack the key/value together into the log entry byte[] packed_update; { MemoryStream writer = new MemoryStream(); // TODO: this seems like a really inefficient way to write out a key ISegmentBlockEncoder encoder = new SegmentBlockBasicEncoder(); encoder.setStream(writer); encoder.add(skey, supdate); encoder.flush(); packed_update = writer.ToArray(); } RecordUpdate logupdate = RecordUpdate.WithPayload(packed_update); Console.WriteLine("writing log entry: {0} -> [ {1} = {2} ]", logkey, skey, supdate); next_stage.setValue(logkey, logupdate); // (2) trigger the repl notifier that there is a new entry to push pusher.wakeUpLogSleepers(); // (2) write the record key Console.WriteLine("writing data entry: {0} = {1}", skey, supdate); RecordKey private_record_key = new RecordKey() .appendKeyPart("_data"); foreach (var part in skey.key_parts) { private_record_key.appendKeyPart(part); } next_stage.setValue(private_record_key, supdate); }
public void T01_BasicBlock_Find() { string[] testvalues = { "test/1", "test/2", "test/3" }; byte[] databuffer; // encode a buffer { MemoryStream ms = new MemoryStream(); // add some values to the block encoder SegmentBlockBasicEncoder enc = new SegmentBlockBasicEncoder(); enc.setStream(ms); for (int i = 0; i < testvalues.Length; i++) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[i]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[i]); enc.add(tkey, tupdate); } enc.flush(); databuffer = ms.ToArray(); } // test FindNext(key,equal_ok=true) { BlockAccessor rs = new BlockAccessor(databuffer); SegmentBlockBasicDecoder decoder = new SegmentBlockBasicDecoder(rs); for (int i = testvalues.Length -1; i >= 0; i--) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[i]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[i]); KeyValuePair<RecordKey,RecordUpdate> row = decoder.FindNext(tkey, true); Assert.AreEqual(tkey, row.Key, "record keys should match"); Assert.AreEqual(tupdate, row.Value, "record values should match:"); } } // test FindNext(key,equal_ok=false) { BlockAccessor rs = new BlockAccessor(databuffer); SegmentBlockBasicDecoder decoder = new SegmentBlockBasicDecoder(rs); for (int i = testvalues.Length - 2; i >= 0; i--) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[i]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[i]); RecordKey fkey = new RecordKey().appendParsedKey(testvalues[i + 1]); RecordUpdate fupdate = RecordUpdate.WithPayload("data: " + testvalues[i+1]); KeyValuePair<RecordKey, RecordUpdate> row = decoder.FindNext(tkey, false); Assert.AreEqual(fkey, row.Key, "findnext(,false) should find next key"); Assert.AreEqual(fupdate, row.Value, "findnext(,false) should finx next key (value was botched)"); } // test for "next" after end of buffer, and we should get an exception // test for "next" at beginning and we should get first // test some random values in the middle } }
public void T02_BasicBlock_Enumerators() { // exercize the iscannable interface string[] testvalues = { "test/1", "test/2", "test/3" }; byte[] databuffer; // encode a buffer { MemoryStream ms = new MemoryStream(); // add some values to the block encoder SegmentBlockBasicEncoder enc = new SegmentBlockBasicEncoder(); enc.setStream(ms); for (int i = 0; i < testvalues.Length; i++) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[i]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[i]); enc.add(tkey, tupdate); } enc.flush(); databuffer = ms.ToArray(); } // decode and test the buffer, scan enumerators { BlockAccessor rs = new BlockAccessor(databuffer); SegmentBlockBasicDecoder decoder = new SegmentBlockBasicDecoder(rs); int pos = 0; IScanner<RecordKey> scanner = ScanRange<RecordKey>.All(); foreach (KeyValuePair<RecordKey, RecordUpdate> row in decoder.scanForward(scanner)) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[pos]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[pos]); Assert.AreEqual(tkey, row.Key, "forward, record keys should match"); Assert.AreEqual(tupdate, row.Value, "forward, record values should match:"); pos++; } Assert.AreEqual(testvalues.Length, pos, "forward, should return all values we put in"); pos = testvalues.Length - 1; foreach (KeyValuePair<RecordKey, RecordUpdate> row in decoder.scanBackward(scanner)) { RecordKey tkey = new RecordKey().appendParsedKey(testvalues[pos]); RecordUpdate tupdate = RecordUpdate.WithPayload("data: " + testvalues[pos]); Assert.AreEqual(tkey, row.Key, "backward, record keys should match, pos=" + pos); Assert.AreEqual(tupdate, row.Value, "backward, record values should match:"); pos--; } Assert.AreEqual(-1, pos, "backward, should return all values we put in"); } }
public void setValue(RecordKey key, RecordUpdate update) { // build a byte[] for the updates using the basic block encoder MemoryStream writer = new MemoryStream(); // TODO: this seems like a really inefficient way to write out a key ISegmentBlockEncoder encoder = new SegmentBlockBasicEncoder(); encoder.setStream(writer); encoder.add(key, update); encoder.flush(); writer.Flush(); this.addCommand((byte)LogCommands.UPDATE, writer.ToArray()); // Writes are actually applied to the workingSegment when the LgoWriter pushes them to the ILogReceiver. // This assures, for example, that DISK_ATOMIC writes to not apply to the segments until the writegroup is flushed. }