http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs new file mode 100644 index 0000000..d1ba5da --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateItemCollection.cs @@ -0,0 +1,534 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.AspNet.Impl +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Collections.Specialized; + using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; + using System.IO; + using System.Linq; + using System.Runtime.Serialization.Formatters.Binary; + using System.Web.SessionState; + using Apache.Ignite.Core.Binary; + using Apache.Ignite.Core.Impl.Common; + + /// <summary> + /// Binarizable key-value collection with dirty item tracking. + /// </summary> + internal class IgniteSessionStateItemCollection : ISessionStateItemCollection + { + /** */ + private readonly Dictionary<string, int> _dict; + + /** */ + private readonly List<Entry> _list; + + /** Indicates where this is a new collection, not a deserialized old one. */ + private readonly bool _isNew; + + /** Removed keys. Hash set because keys can be removed multiple times. */ + private HashSet<string> _removedKeys; + + /** Indicates that entire collection is dirty and can't be written as a diff. */ + private bool _dirtyAll; + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteSessionStateItemCollection"/> class. + /// </summary> + /// <param name="reader">The binary reader.</param> + internal IgniteSessionStateItemCollection(IBinaryRawReader reader) + { + Debug.Assert(reader != null); + + var count = reader.ReadInt(); + + _dict = new Dictionary<string, int>(count); + _list = new List<Entry>(count); + + for (var i = 0; i < count; i++) + { + var key = reader.ReadString(); + + var valBytes = reader.ReadByteArray(); + + if (valBytes != null) + { + var entry = new Entry(key, true, valBytes); + + _dict[key] = _list.Count; + + _list.Add(entry); + } + else + AddRemovedKey(key); + } + + _isNew = false; + } + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteSessionStateItemCollection"/> class. + /// </summary> + public IgniteSessionStateItemCollection() + { + _dict = new Dictionary<string, int>(); + _list = new List<Entry>(); + _isNew = true; + } + + /** <inheritdoc /> */ + [SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", + Justification = "Validation is present.")] + public void CopyTo(Array array, int index) + { + IgniteArgumentCheck.NotNull(array, "array"); + IgniteArgumentCheck.Ensure(Count + index < array.Length, "array", + "The number of elements in the source collection is greater than the available space " + + "from specified index to the end of the array."); + + // This should return only keys. + foreach (var entry in _list) + array.SetValue(entry.Key, index++); + } + + /** <inheritdoc /> */ + public IEnumerator GetEnumerator() + { + // This should return only keys. + return _list.Select(x => x.Key).GetEnumerator(); + } + + /** <inheritdoc /> */ + public int Count + { + get { return _dict.Count; } + } + + /** <inheritdoc /> */ + public object SyncRoot + { + get { return _list; } + } + + /** <inheritdoc /> */ + public bool IsSynchronized + { + get { return false; } + } + + /** <inheritdoc /> */ + public object this[string key] + { + get + { + var entry = GetEntry(key); + + if (entry == null) + return null; + + SetDirtyOnRead(entry); + + return entry.Value; + } + set + { + var entry = GetOrCreateDirtyEntry(key); + + entry.Value = value; + } + } + + /** <inheritdoc /> */ + public object this[int index] + { + get + { + var entry = _list[index]; + + SetDirtyOnRead(entry); + + return entry.Value; + } + set + { + var entry = _list[index]; + + entry.IsDirty = true; + + entry.Value = value; + } + } + + /** <inheritdoc /> */ + public NameObjectCollectionBase.KeysCollection Keys + { + get { return new NameObjectCollection(this).Keys; } + } + + + /** <inheritdoc /> */ + public bool Dirty + { + get { return _dirtyAll || _list.Any(x => x.IsDirty); } + set { _dirtyAll = value; } + } + + /// <summary> + /// Writes this object to the given writer. + /// </summary> + public void WriteBinary(IBinaryRawWriter writer, bool changesOnly) + { + IgniteArgumentCheck.NotNull(writer, "writer"); + + if (_isNew || _dirtyAll || !changesOnly || (_removedKeys == null && _list.All(x => x.IsDirty))) + { + // Write in full mode. + writer.WriteInt(_list.Count); + + foreach (var entry in _list) + { + writer.WriteString(entry.Key); + + // Write as byte array to enable partial deserialization. + writer.WriteByteArray(entry.GetBytes()); + } + } + else + { + // Write in diff mode. + var removed = GetRemovedKeys(); + + var count = _list.Count(x => x.IsDirty) + (removed == null ? 0 : removed.Count); + + writer.WriteInt(count); // reserve count + + // Write removed keys as [key + null]. + if (removed != null) + { + foreach (var removedKey in removed) + { + writer.WriteString(removedKey); + writer.WriteByteArray(null); + } + } + + // Write dirty items. + foreach (var entry in _list) + { + if (!entry.IsDirty) + continue; + + writer.WriteString(entry.Key); + + // Write as byte array to enable partial deserialization. + writer.WriteByteArray(entry.GetBytes()); + } + } + } + + /// <summary> + /// Gets the removed keys. + /// </summary> + private ICollection<string> GetRemovedKeys() + { + if (_removedKeys == null) + return null; + + // Filter out existing keys. + var removed = new HashSet<string>(_removedKeys); + + foreach (var entry in _list) + removed.Remove(entry.Key); + + return removed; + } + + /// <summary> + /// Removes the specified key. + /// </summary> + public void Remove(string key) + { + var index = GetIndex(key); + + if (index < 0) + return; + + var entry = _list[index]; + Debug.Assert(key == entry.Key); + + _list.RemoveAt(index); + _dict.Remove(key); + + // Update all indexes. + for (var i = 0; i < _list.Count; i++) + _dict[_list[i].Key] = i; + + if (entry.IsInitial) + AddRemovedKey(key); + } + + /// <summary> + /// Removes at specified index. + /// </summary> + public void RemoveAt(int index) + { + var entry = _list[index]; + + _list.RemoveAt(index); + _dict.Remove(entry.Key); + + if (entry.IsInitial) + AddRemovedKey(entry.Key); + } + + /// <summary> + /// Clears this instance. + /// </summary> + public void Clear() + { + foreach (var entry in _list) + { + if (entry.IsInitial) + AddRemovedKey(entry.Key); + } + + _list.Clear(); + _dict.Clear(); + + _dirtyAll = true; + } + + /// <summary> + /// Applies the changes. + /// </summary> + public void ApplyChanges(IgniteSessionStateItemCollection changes) + { + var removed = changes._removedKeys; + + if (removed != null) + { + foreach (var key in removed) + Remove(key); + } + else + { + // Not a diff: replace all. + Clear(); + } + + foreach (var changedEntry in changes._list) + { + var entry = GetOrCreateDirtyEntry(changedEntry.Key); + + // Copy without deserialization. + changedEntry.CopyTo(entry); + } + } + + /// <summary> + /// Adds the removed key. + /// </summary> + private void AddRemovedKey(string key) + { + Debug.Assert(!_isNew); + + if (_removedKeys == null) + _removedKeys = new HashSet<string>(); + + _removedKeys.Add(key); + } + + /// <summary> + /// Gets or creates an entry. + /// </summary> + private Entry GetOrCreateDirtyEntry(string key) + { + var entry = GetEntry(key); + + if (entry == null) + { + entry = new Entry(key, false, null); + + _dict[key] = _list.Count; + _list.Add(entry); + } + + entry.IsDirty = true; + + return entry; + } + + /// <summary> + /// Gets the entry. + /// </summary> + private Entry GetEntry(string key) + { + IgniteArgumentCheck.NotNull(key, "key"); + + int index; + + return !_dict.TryGetValue(key, out index) ? null : _list[index]; + } + + /// <summary> + /// Gets the index. + /// </summary> + private int GetIndex(string key) + { + int index; + + return !_dict.TryGetValue(key, out index) ? -1 : index; + } + + /// <summary> + /// Sets the dirty on read. + /// </summary> + private static void SetDirtyOnRead(Entry entry) + { + var type = entry.Value.GetType(); + + if (IsImmutable(type)) + return; + + entry.IsDirty = true; + } + + /// <summary> + /// Determines whether the specified type is immutable. + /// </summary> + private static bool IsImmutable(Type type) + { + type = Nullable.GetUnderlyingType(type) ?? type; // Unwrap nullable. + + if (type.IsPrimitive) + return true; + + if (type == typeof(string) || type == typeof(DateTime) || type == typeof(Guid) || type == typeof(decimal)) + return true; + + return false; + } + + /// <summary> + /// Inner entry. + /// </summary> + private class Entry + { + /** */ + public readonly bool IsInitial; + + /** */ + public readonly string Key; + + /** */ + public bool IsDirty; + + /** */ + private object _value; + + /** */ + private bool _isDeserialized; + + /// <summary> + /// Initializes a new instance of the <see cref="Entry"/> class. + /// </summary> + public Entry(string key, bool isInitial, object value) + { + Debug.Assert(key != null); + + Key = key; + IsInitial = isInitial; + _isDeserialized = !isInitial; + _value = value; + } + + /// <summary> + /// Gets or sets the value. + /// </summary> + public object Value + { + get + { + if (!_isDeserialized) + { + using (var stream = new MemoryStream((byte[])_value)) + { + _value = new BinaryFormatter().Deserialize(stream); + } + + _isDeserialized = true; + } + + return _value; + } + set + { + _value = value; + _isDeserialized = true; + } + } + + /// <summary> + /// Copies contents to another entry. + /// </summary> + public void CopyTo(Entry entry) + { + Debug.Assert(entry != null); + + entry._isDeserialized = _isDeserialized; + entry._value = _value; + } + + /// <summary> + /// Gets the bytes. + /// </summary> + public byte[] GetBytes() + { + if (!_isDeserialized) + return (byte[]) _value; + + using (var stream = new MemoryStream()) + { + new BinaryFormatter().Serialize(stream, _value); + + return stream.ToArray(); + } + } + } + + /// <summary> + /// NameObjectCollectionBase.KeysCollection has internal constructor. + /// The only way to implement ISessionStateItemCollection.Keys property + /// is to have a NameObjectCollectionBase in hand. + /// </summary> + private class NameObjectCollection : NameObjectCollectionBase + { + /// <summary> + /// Initializes a new instance of the <see cref="NameObjectCollection"/> class. + /// </summary> + public NameObjectCollection(IEnumerable keys) + { + foreach (string key in keys) + BaseAdd(key, null); + } + } + } +}
http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs new file mode 100644 index 0000000..32c36b5 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/IgniteSessionStateStoreData.cs @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.AspNet.Impl +{ + using System; + using System.IO; + using System.Web; + using System.Web.SessionState; + using Apache.Ignite.Core.Binary; + + /// <summary> + /// Ignite <see cref="SessionStateStoreData"/> implementation. + /// </summary> + internal class IgniteSessionStateStoreData : SessionStateStoreData + { + /// <summary> + /// Initializes a new instance of the <see cref="IgniteSessionStateStoreData"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public IgniteSessionStateStoreData(IBinaryRawReader reader) : base( + new IgniteSessionStateItemCollection(reader), + DeserializeStaticObjects(reader.ReadByteArray()), reader.ReadInt()) + { + LockNodeId = reader.ReadGuid(); + LockId = reader.ReadLong(); + LockTime = reader.ReadTimestamp(); + } + + /// <summary> + /// Initializes a new instance of the <see cref="IgniteSessionStateStoreData"/> class. + /// </summary> + /// <param name="staticObjects">The static objects.</param> + /// <param name="timeout">The timeout.</param> + public IgniteSessionStateStoreData(HttpStaticObjectsCollection staticObjects, int timeout) + : base(new IgniteSessionStateItemCollection(), staticObjects, timeout) + { + // No-op. + } + + /// <summary> + /// Writes this object to the given writer. + /// </summary> + public void WriteBinary(IBinaryRawWriter writer, bool changesOnly) + { + ((IgniteSessionStateItemCollection)Items).WriteBinary(writer, changesOnly); + writer.WriteByteArray(SerializeStaticObjects()); + writer.WriteInt(Timeout); + + writer.WriteGuid(LockNodeId); + writer.WriteLong(LockId); + writer.WriteTimestamp(LockTime); + } + + /// <summary> + /// Gets or sets the lock node id. Null means not locked. + /// </summary> + public Guid? LockNodeId { get; set; } + + /// <summary> + /// Gets or sets the lock id. + /// </summary> + public long LockId { get; set; } + + /// <summary> + /// Gets or sets the lock time. + /// </summary> + public DateTime? LockTime { get; set; } + + /// <summary> + /// Deserializes the static objects. + /// </summary> + private static HttpStaticObjectsCollection DeserializeStaticObjects(byte[] bytes) + { + if (bytes == null) + return new HttpStaticObjectsCollection(); + + using (var stream = new MemoryStream(bytes)) + using (var reader = new BinaryReader(stream)) + { + return HttpStaticObjectsCollection.Deserialize(reader); + } + } + + /// <summary> + /// Serializes the static objects. + /// </summary> + private byte[] SerializeStaticObjects() + { + if (StaticObjects == null || StaticObjects.Count == 0) + return null; + + using (var stream = new MemoryStream()) + using (var writer = new BinaryWriter(stream)) + { + StaticObjects.Serialize(writer); + + return stream.ToArray(); + } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs new file mode 100644 index 0000000..ebca8e0 --- /dev/null +++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Impl/SessionStateLockResult.cs @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +namespace Apache.Ignite.AspNet.Impl +{ + using System; + using System.Diagnostics; + using Apache.Ignite.Core.Binary; + + /// <summary> + /// Result of the session state lock processor. + /// </summary> + internal class SessionStateLockResult + { + /** Success flag. */ + private readonly bool _success; + + /** Session state data. */ + private readonly IgniteSessionStateStoreData _data; + + /** Lock time. */ + private readonly DateTime? _lockTime; + + /** Lock id. */ + private readonly long _lockId; + + /// <summary> + /// Initializes a new instance of the <see cref="SessionStateLockResult"/> class. + /// </summary> + /// <param name="reader">The reader.</param> + public SessionStateLockResult(IBinaryRawReader reader) + { + _success = reader.ReadBoolean(); + + if (_success) + _data = new IgniteSessionStateStoreData(reader); + + _lockTime = reader.ReadTimestamp(); + _lockId = reader.ReadLong(); + + Debug.Assert(_success ^ (_data == null)); + Debug.Assert(_success ^ (_lockTime != null)); + } + + /// <summary> + /// Gets a value indicating whether lock succeeded. + /// </summary> + public bool Success + { + get { return _success; } + } + + /// <summary> + /// Gets the data. Null when <see cref="Success"/> is <c>false</c>. + /// </summary> + public IgniteSessionStateStoreData Data + { + get { return _data; } + } + + /// <summary> + /// Gets the lock time. Null when <see cref="Success"/> is <c>true</c>. + /// </summary> + public DateTime? LockTime + { + get { return _lockTime; } + } + + /// <summary> + /// Gets the lock identifier. + /// </summary> + public long LockId + { + get { return _lockId; } + } + } +} http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs b/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs index ad61ecd..2a7da67 100644 --- a/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs +++ b/modules/platforms/dotnet/Apache.Ignite.AspNet/Properties/AssemblyInfo.cs @@ -17,6 +17,7 @@ using System; using System.Reflection; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; [assembly: AssemblyTitle("Apache.Ignite.AspNet")] @@ -36,4 +37,6 @@ using System.Runtime.InteropServices; [assembly: AssemblyFileVersion("1.8.0.14218")] [assembly: AssemblyInformationalVersion("1.8.0")] -[assembly: CLSCompliant(true)] \ No newline at end of file +[assembly: CLSCompliant(true)] + +[assembly: InternalsVisibleTo("Apache.Ignite.AspNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9380ce05eb74bd7c531f72e9ea615c59d7eceb09bd9795cb3dff1fcf638fd799c2a58a9be42fff156efe1c8cdebb751e27763f6c9a7c80cdc1dc1bbf44283608ef18ccd5017fd57b2b026503637c89c2537f361807f3bdd49265f4d444716159d989342561d324b1a0961640338bb32eaf67f4ae0c95f1b210f65404b0909c6")] \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj index 95fea8f..b1e0dbe 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/Apache.Ignite.Core.Tests.csproj @@ -49,13 +49,11 @@ <Reference Include="System.configuration" /> <Reference Include="System.Core" /> <Reference Include="System.Runtime.Serialization" /> - <Reference Include="System.Web" /> <Reference Include="System.ServiceProcess" /> <Reference Include="System.XML" /> </ItemGroup> <ItemGroup> <Compile Include="TestAppConfig.cs" /> - <Compile Include="AspNet\IgniteOutputCacheProviderTest.cs" /> <Compile Include="Binary\BinaryBuilderSelfTestFullFooter.cs" /> <Compile Include="Binary\BinaryCompactFooterInteropTest.cs" /> <Compile Include="Binary\BinarySelfTestFullFooter.cs" /> @@ -167,10 +165,6 @@ <Compile Include="WindowsServiceTest.cs" /> </ItemGroup> <ItemGroup> - <ProjectReference Include="..\Apache.Ignite.AspNet\Apache.Ignite.AspNet.csproj"> - <Project>{13EA96FC-CC83-4164-A7C0-4F30ED797460}</Project> - <Name>Apache.Ignite.AspNet</Name> - </ProjectReference> <ProjectReference Include="..\Apache.Ignite.Core\Apache.Ignite.Core.csproj"> <Project>{4CD2F726-7E2B-46C4-A5BA-057BB82EECB6}</Project> <Name>Apache.Ignite.Core</Name> http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs deleted file mode 100644 index 51bfdc1..0000000 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/AspNet/IgniteOutputCacheProviderTest.cs +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace Apache.Ignite.Core.Tests.AspNet -{ - using System; - using System.Collections.Specialized; - using System.Threading; - using Apache.Ignite.AspNet; - using Apache.Ignite.Core.Common; - using NUnit.Framework; - - /// <summary> - /// Tests for <see cref="IgniteOutputCacheProvider"/> - /// </summary> - public class IgniteOutputCacheProviderTest - { - /** Grid name XML config attribute. */ - private const string GridNameAttr = "gridName"; - - /** Cache name XML config attribute. */ - private const string CacheNameAttr = "cacheName"; - - /** Cache name XML config attribute. */ - private const string SectionNameAttr = "igniteConfigurationSectionName"; - - /** Grid name. */ - private const string GridName = "grid1"; - - /** Cache name. */ - private const string CacheName = "myCache"; - - /// <summary> - /// Fixture setup. - /// </summary> - [TestFixtureSetUp] - public void TestFixtureSetUp() - { - Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration()) {GridName = GridName}); - } - - /// <summary> - /// Fixture teardown. - /// </summary> - [TestFixtureTearDown] - public void TestFixtureTearDown() - { - Ignition.StopAll(true); - } - - /// <summary> - /// Tests provider initialization. - /// </summary> - [Test] - public void TestInitialization() - { - var cacheProvider = new IgniteOutputCacheProvider(); - - // Not initialized - Assert.Throws<InvalidOperationException>(() => cacheProvider.Get("1")); - - // Grid not started - Assert.Throws<IgniteException>(() => - cacheProvider.Initialize("testName", new NameValueCollection - { - {GridNameAttr, "invalidGridName"}, - {CacheNameAttr, CacheName} - })); - - // Valid grid - cacheProvider = GetProvider(); - - cacheProvider.Set("1", 1, DateTime.MaxValue); - Assert.AreEqual(1, cacheProvider.Get("1")); - } - - /// <summary> - /// Tests autostart from web configuration section. - /// </summary> - [Test] - public void TestStartFromWebConfigSection() - { - var cacheProvider = new IgniteOutputCacheProvider(); - - cacheProvider.Initialize("testName2", new NameValueCollection - { - {SectionNameAttr, "igniteConfiguration2"}, - {CacheNameAttr, "cacheName2"} - }); - - cacheProvider.Set("1", 3, DateTime.MaxValue); - Assert.AreEqual(3, cacheProvider.Get("1")); - } - - /// <summary> - /// Tests provider caching. - /// </summary> - [Test] - public void TestCaching() - { - var cacheProvider = GetProvider(); - - Assert.AreEqual(null, cacheProvider.Get("1")); - cacheProvider.Set("1", 1, DateTime.MaxValue); - Assert.AreEqual(1, cacheProvider.Get("1")); - - cacheProvider.Remove("1"); - Assert.AreEqual(null, cacheProvider.Get("1")); - - Assert.AreEqual(null, cacheProvider.Add("2", 2, DateTime.MaxValue)); - Assert.AreEqual(2, cacheProvider.Add("2", 5, DateTime.MaxValue)); - } - - /// <summary> - /// Tests cache expiration. - /// </summary> - [Test] - public void TestExpiry() - { - var cacheProvider = GetProvider(); - cacheProvider.Remove("1"); - - // Set - cacheProvider.Set("1", 1, DateTime.UtcNow.AddSeconds(1.3)); - Assert.AreEqual(1, cacheProvider.Get("1")); - Thread.Sleep(2000); - Assert.AreEqual(null, cacheProvider.Get("1")); - - cacheProvider.Set("1", 1, DateTime.UtcNow); - Assert.AreEqual(null, cacheProvider.Get("1")); - - // Add - cacheProvider.Add("1", 1, DateTime.UtcNow.AddSeconds(0.7)); - Assert.AreEqual(1, cacheProvider.Get("1")); - Thread.Sleep(2000); - Assert.AreEqual(null, cacheProvider.Get("1")); - - cacheProvider.Add("1", 1, DateTime.UtcNow); - Assert.AreEqual(null, cacheProvider.Get("1")); - } - - /// <summary> - /// Gets the initialized provider. - /// </summary> - private static IgniteOutputCacheProvider GetProvider() - { - var cacheProvider = new IgniteOutputCacheProvider(); - - cacheProvider.Initialize("testName", new NameValueCollection - { - {GridNameAttr, GridName}, - {CacheNameAttr, CacheName} - }); - - return cacheProvider; - } - } -} http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs index c0b8599..6ca2f9d 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core.Tests/TestUtils.cs @@ -23,7 +23,6 @@ namespace Apache.Ignite.Core.Tests using System.Collections.Generic; using System.Linq; using System.Threading; - using Apache.Ignite.Core.Discovery; using Apache.Ignite.Core.Discovery.Tcp; using Apache.Ignite.Core.Discovery.Tcp.Static; using Apache.Ignite.Core.Impl; http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs index 8ba3e29..fb47f29 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheImpl.cs @@ -872,6 +872,21 @@ namespace Apache.Ignite.Core.Impl.Cache return AsyncInstance.GetTask(CacheOp.InvokeAll, reader => ReadInvokeAllResults<TRes>(reader.Stream)); } + /** <inheritDoc /> */ + public T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction, + Func<IBinaryRawReader, T> readFunc) + { + return DoOutInOpX((int) CacheOp.Extension, writer => + { + writer.WriteInt(extensionId); + writer.WriteInt(opCode); + writeAction(writer); + }, + (input, res) => res == True + ? readFunc(Marshaller.StartUnmarshal(input)) + : default(T), ReadException); + } + /** <inheritdoc /> */ public ICacheLock Lock(TK key) { http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs index 4c42bf3..e6ca938 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/CacheOp.cs @@ -61,6 +61,7 @@ namespace Apache.Ignite.Core.Impl.Cache Replace2 = 37, Replace3 = 38, GetConfig = 39, - LoadAll = 40 + LoadAll = 40, + Extension = 41 } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs index a23cf08..0349db8 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Cache/ICacheInternal.cs @@ -36,5 +36,19 @@ namespace Apache.Ignite.Core.Impl.Cache /// Cursor. /// </returns> IQueryCursor<T> QueryFields<T>(SqlFieldsQuery qry, Func<IBinaryRawReader, int, T> readerFunc); + + /// <summary> + /// Invokes a cache extension. + /// </summary> + /// <typeparam name="T">The type of the result.</typeparam> + /// <param name="extensionId">The extension identifier.</param> + /// <param name="opCode">The extension op code.</param> + /// <param name="writeAction">The write action.</param> + /// <param name="readFunc">The read action.</param> + /// <returns> + /// Result of the processing. + /// </returns> + T DoOutInOpExtension<T>(int extensionId, int opCode, Action<IBinaryRawWriter> writeAction, + Func<IBinaryRawReader, T> readFunc); } } http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs index fd52c8a..4ee67dd 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Unmanaged/UnmanagedCallbacks.cs @@ -21,7 +21,6 @@ namespace Apache.Ignite.Core.Impl.Unmanaged using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; - using System.Globalization; using System.IO; using System.Runtime.InteropServices; using System.Threading; http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs index 008ba5c..9fcbeb0 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Properties/AssemblyInfo.cs @@ -43,5 +43,6 @@ using System.Runtime.InteropServices; [assembly: InternalsVisibleTo("Apache.Ignite.Core.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a5bf8e0062a26bde53ccf0f8c42ef5b122a22052f99aecacb7028adcc163050324ee3c75ff40eb0cbe2d0426fa20eca03726cad90d7eb882ff47f5361567a82b676a27565f88b2479d7b9354ae0a1e526ee781b6e11de943d8f4a49efb53765f8c954022bede0fca86c133fab038af8dc88b67d6b6e5b9796d6ca490e699efab")] [assembly: InternalsVisibleTo("Apache.Ignite.Benchmarks, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a3e0c1df4cbedbd4ed0e88808401c69b69ec12575ed1c056ac9f448e018fb29af19d236b7b03563aad66c48ab2045e72971ed098d4f65d4cdd38d65abcb39b4f84c626b22ccab2754375f0e8c97dc304fa146f0eddad5cc40a71803a8f15b0b0bb0bff0d4bf0ff6a64bb1044e0d71e6e2405b83fd4c1f7b3e2cfc2e9d50823d4")] +[assembly: InternalsVisibleTo("Apache.Ignite.AspNet.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c9380ce05eb74bd7c531f72e9ea615c59d7eceb09bd9795cb3dff1fcf638fd799c2a58a9be42fff156efe1c8cdebb751e27763f6c9a7c80cdc1dc1bbf44283608ef18ccd5017fd57b2b026503637c89c2537f361807f3bdd49265f4d444716159d989342561d324b1a0961640338bb32eaf67f4ae0c95f1b210f65404b0909c6")] #endif http://git-wip-us.apache.org/repos/asf/ignite/blob/799f1909/modules/platforms/dotnet/Apache.Ignite.sln ---------------------------------------------------------------------- diff --git a/modules/platforms/dotnet/Apache.Ignite.sln b/modules/platforms/dotnet/Apache.Ignite.sln index 2362ce2..8a3bf04 100644 --- a/modules/platforms/dotnet/Apache.Ignite.sln +++ b/modules/platforms/dotnet/Apache.Ignite.sln @@ -36,6 +36,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.Linq", "Apach EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.AspNet", "Apache.Ignite.AspNet\Apache.Ignite.AspNet.csproj", "{13EA96FC-CC83-4164-A7C0-4F30ED797460}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Apache.Ignite.AspNet.Tests", "Apache.Ignite.AspNet.Tests\Apache.Ignite.AspNet.Tests.csproj", "{18EA4C71-A11D-4AB1-8042-418F7559D84F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -174,6 +176,18 @@ Global {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x64.Build.0 = Release|Any CPU {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x86.ActiveCfg = Release|Any CPU {13EA96FC-CC83-4164-A7C0-4F30ED797460}.Release|x86.Build.0 = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x64.ActiveCfg = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x64.Build.0 = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x86.ActiveCfg = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Debug|x86.Build.0 = Debug|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|Any CPU.Build.0 = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x64.ActiveCfg = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x64.Build.0 = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x86.ActiveCfg = Release|Any CPU + {18EA4C71-A11D-4AB1-8042-418F7559D84F}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE