/// <summary> /// Decompresses the items. /// </summary> private void DecompressItems() { ErrorUtilities.VerifyThrow(_uncompressedItems == null, "Items already decompressed."); using (MemoryStream serializedStream = new MemoryStream(_compressedItems, 0, _compressedItems.Length, writable: false, publiclyVisible: true)) { using (DeflateStream inflateStream = new DeflateStream(serializedStream, CompressionMode.Decompress)) { INodePacketTranslator serializedBufferTranslator = NodePacketTranslator.GetReadTranslator(inflateStream, null); LookasideStringInterner interner = new LookasideStringInterner(serializedBufferTranslator); byte[] buffer = null; serializedBufferTranslator.Translate(ref buffer); ErrorUtilities.VerifyThrow(buffer != null, "Unexpected null items buffer during decompression."); using (MemoryStream itemsStream = new MemoryStream(buffer, 0, buffer.Length, writable: false, publiclyVisible: true)) { INodePacketTranslator itemTranslator = NodePacketTranslator.GetReadTranslator(itemsStream, null); _uncompressedItems = new TaskItem[_itemsCount]; for (int i = 0; i < _uncompressedItems.Length; i++) { _uncompressedItems[i] = TaskItem.FactoryForDeserialization(itemTranslator, interner); } } } } _compressedItems = null; }
public void ReuseOfDeserializedInternerNotAllowed() { var interner = new LookasideStringInterner(StringComparer.OrdinalIgnoreCase, 1); int strIndex = interner.Intern("abc123def456"); MemoryStream stream = new MemoryStream(); INodePacketTranslator writetranslator = NodePacketTranslator.GetWriteTranslator(stream); interner.Translate(writetranslator); INodePacketTranslator readtranslator = NodePacketTranslator.GetReadTranslator(stream, null); var newInterner = new LookasideStringInterner(readtranslator); bool gotException = false; try { newInterner.Intern("foo"); } catch (Exception) { gotException = true; } Assert.IsTrue(gotException); }
public void ComparerIsObeyed() { var interner = new LookasideStringInterner(StringComparer.OrdinalIgnoreCase, 1); int strIndex = interner.Intern("abc123def456"); Assert.AreEqual(interner.Intern("ABC123DEF456"), strIndex); var interner2 = new LookasideStringInterner(StringComparer.Ordinal, 1); int strIndex2 = interner2.Intern("abc123def456"); Assert.AreNotEqual(interner.Intern("ABC123DEF456"), strIndex2); }
public void BasicInterning() { var interner = new LookasideStringInterner(StringComparer.OrdinalIgnoreCase, 1); int nullIndex = interner.Intern(null); int emptyIndex = interner.Intern(String.Empty); int strIndex = interner.Intern("abc123def456"); Assert.AreEqual(interner.Intern(null), nullIndex); Assert.AreEqual(interner.Intern(String.Empty), emptyIndex); Assert.AreEqual(interner.Intern("abc123def456"), strIndex); Assert.AreEqual(interner.GetString(nullIndex), null); Assert.AreEqual(interner.GetString(emptyIndex), String.Empty); Assert.AreEqual(interner.GetString(strIndex), "abc123def456"); }
/// <summary> /// Compresses the items. /// </summary> private void CompressItems() { ErrorUtilities.VerifyThrow(_compressedItems == null, "Items already compressed."); // We will just calculate a very rough starting buffer size for the memory stream based on the number of items and a // rough guess for an average number of bytes needed to store them compressed. This doesn't have to be accurate, just // big enough to avoid unnecessary buffer reallocations in most cases. int defaultCompressedBufferCapacity = _uncompressedItems.Length * 64; using (MemoryStream serializedStream = new MemoryStream(defaultCompressedBufferCapacity)) { using (DeflateStream deflateStream = new DeflateStream(serializedStream, CompressionMode.Compress)) { INodePacketTranslator serializedBufferTranslator = NodePacketTranslator.GetWriteTranslator(deflateStream); // Again, a rough calculation of buffer size, this time for an uncompressed buffer. We assume compression // will give us 2:1, as it's all text. int defaultUncompressedBufferCapacity = defaultCompressedBufferCapacity * 2; using (MemoryStream itemsStream = new MemoryStream(defaultUncompressedBufferCapacity)) { INodePacketTranslator itemTranslator = NodePacketTranslator.GetWriteTranslator(itemsStream); // When creating the interner, we use the number of items as the initial size of the collections since the // number of strings will be of the order of the number of items in the collection. This assumes basically // one unique string per item (frequently a path related to the item) with most of the rest of the metadata // being the same (and thus interning.) This is a hueristic meant to get us in the ballpark to avoid // too many reallocations when growing the collections. LookasideStringInterner interner = new LookasideStringInterner(StringComparer.Ordinal, _uncompressedItems.Length); for (int i = 0; i < _uncompressedItems.Length; i++) { _uncompressedItems[i].TranslateWithInterning(itemTranslator, interner); } interner.Translate(serializedBufferTranslator); byte[] buffer = itemsStream.ToArray(); serializedBufferTranslator.Translate(ref buffer); } } _compressedItems = serializedStream.ToArray(); } _uncompressedItems = null; }
public void Serialization() { var interner = new LookasideStringInterner(StringComparer.OrdinalIgnoreCase, 1); int nullIndex = interner.Intern(null); int emptyIndex = interner.Intern(String.Empty); int strIndex = interner.Intern("abc123def456"); MemoryStream stream = new MemoryStream(); INodePacketTranslator writetranslator = NodePacketTranslator.GetWriteTranslator(stream); interner.Translate(writetranslator); INodePacketTranslator readtranslator = NodePacketTranslator.GetReadTranslator(stream, null); var newInterner = new LookasideStringInterner(readtranslator); Assert.AreEqual(newInterner.GetString(nullIndex), null); Assert.AreEqual(newInterner.GetString(emptyIndex), String.Empty); Assert.AreEqual(newInterner.GetString(strIndex), "abc123def456"); }
public void Empty() { var interner = new LookasideStringInterner(StringComparer.OrdinalIgnoreCase, 1); interner.GetString(0); }