ignite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sboi...@apache.org
Subject [33/33] ignite git commit: ignite-6149
Date Wed, 20 Sep 2017 12:48:31 GMT
ignite-6149


Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/3d161614
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/3d161614
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/3d161614

Branch: refs/heads/ignite-3478
Commit: 3d161614145a92e0009731ad4239e4da90211c40
Parents: e0103a8
Author: sboikov <sboikov@gridgain.com>
Authored: Wed Sep 20 15:45:40 2017 +0300
Committer: sboikov <sboikov@gridgain.com>
Committed: Wed Sep 20 15:47:47 2017 +0300

----------------------------------------------------------------------
 .../configuration/CacheConfiguration.java       | 26 ------
 .../configuration/IgniteConfiguration.java      | 25 +++++
 .../processors/cache/CacheGroupContext.java     | 24 ++++-
 .../processors/cache/ClusterCachesInfo.java     |  6 +-
 .../processors/cache/GridCacheAttributes.java   |  7 --
 .../processors/cache/GridCacheContext.java      |  2 +-
 .../processors/cache/GridCacheProcessor.java    | 13 +--
 ...TransactionsConfigurationValidationTest.java | 96 ++++++++++++++++++++
 .../cache/mvcc/CacheMvccTransactionsTest.java   |  5 +-
 .../org/apache/ignite/yardstick/IgniteNode.java |  6 +-
 10 files changed, 155 insertions(+), 55 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
index b475a6a..1c673e3 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/CacheConfiguration.java
@@ -354,9 +354,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K,
V> {
     /** Cache key configuration. */
     private CacheKeyConfiguration[] keyCfg;
 
-    /** */
-    private boolean mvccEnabled;
-
     /** Empty constructor (all values are initialized to their defaults). */
     public CacheConfiguration() {
         /* No-op. */
@@ -411,7 +408,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K,
V> {
         longQryWarnTimeout = cc.getLongQueryWarningTimeout();
         maxConcurrentAsyncOps = cc.getMaxConcurrentAsyncOperations();
         memPlcName = cc.getMemoryPolicyName();
-        mvccEnabled = cc.isMvccEnabled();
         name = cc.getName();
         nearCfg = cc.getNearConfiguration();
         nodeFilter = cc.getNodeFilter();
@@ -2010,27 +2006,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K,
V> {
     }
 
     /**
-     * TODO IGNITE-3478
-     *
-     * @return
-     */
-    public boolean isMvccEnabled() {
-        return mvccEnabled;
-    }
-
-    /**
-     * TODO IGNITE-3478
-     *
-     * @param mvccEnabled
-     * @return {@code this} for chaining.
-     */
-    public CacheConfiguration<K, V> setMvccEnabled(boolean mvccEnabled) {
-        this.mvccEnabled = mvccEnabled;
-
-        return this;
-    }
-
-    /**
      * Creates a copy of current configuration and removes all cache entry listeners.
      * They are executed only locally and should never be sent to remote nodes.
      *
@@ -2044,7 +2019,6 @@ public class CacheConfiguration<K, V> extends MutableConfiguration<K,
V> {
         return cfg;
     }
 
-
     /**
      * @param cls Class.
      * @return Masked class.

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
index 6e91b10..990159b 100644
--- a/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
+++ b/modules/core/src/main/java/org/apache/ignite/configuration/IgniteConfiguration.java
@@ -475,6 +475,9 @@ public class IgniteConfiguration {
     /** Client connector configuration. */
     private ClientConnectorConfiguration cliConnCfg = ClientListenerProcessor.DFLT_CLI_CFG;
 
+    /** */
+    private boolean mvccEnabled;
+
     /**
      * Creates valid grid configuration with all default values.
      */
@@ -549,6 +552,7 @@ public class IgniteConfiguration {
         metricsLogFreq = cfg.getMetricsLogFrequency();
         metricsUpdateFreq = cfg.getMetricsUpdateFrequency();
         mgmtPoolSize = cfg.getManagementThreadPoolSize();
+        mvccEnabled = cfg.isMvccEnabled();
         netTimeout = cfg.getNetworkTimeout();
         nodeId = cfg.getNodeId();
         odbcCfg = cfg.getOdbcConfiguration();
@@ -2844,6 +2848,27 @@ public class IgniteConfiguration {
         return cliConnCfg;
     }
 
+    /**
+     * TODO IGNITE-3478
+     *
+     * @return
+     */
+    public boolean isMvccEnabled() {
+        return mvccEnabled;
+    }
+
+    /**
+     * TODO IGNITE-3478
+     *
+     * @param mvccEnabled
+     * @return {@code this} for chaining.
+     */
+    public IgniteConfiguration setMvccEnabled(boolean mvccEnabled) {
+        this.mvccEnabled = mvccEnabled;
+
+        return this;
+    }
+
     /** {@inheritDoc} */
     @Override public String toString() {
         return S.toString(IgniteConfiguration.class, this);

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
index df21d1b..6e29dcc 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheGroupContext.java
@@ -26,10 +26,12 @@ import java.util.Set;
 import java.util.UUID;
 import org.apache.ignite.IgniteCheckedException;
 import org.apache.ignite.IgniteLogger;
+import org.apache.ignite.cache.CacheAtomicityMode;
 import org.apache.ignite.cache.affinity.AffinityFunction;
 import org.apache.ignite.cluster.ClusterNode;
 import org.apache.ignite.configuration.CacheConfiguration;
 import org.apache.ignite.configuration.DataPageEvictionMode;
+import org.apache.ignite.configuration.IgniteConfiguration;
 import org.apache.ignite.configuration.TopologyValidator;
 import org.apache.ignite.events.CacheRebalancingEvent;
 import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException;
@@ -58,6 +60,7 @@ import org.apache.ignite.lang.IgnitePredicate;
 import org.apache.ignite.lang.IgniteUuid;
 import org.jetbrains.annotations.Nullable;
 
+import static org.apache.ignite.cache.CacheAtomicityMode.*;
 import static org.apache.ignite.cache.CacheMode.LOCAL;
 import static org.apache.ignite.cache.CacheMode.REPLICATED;
 import static org.apache.ignite.cache.CacheRebalanceMode.NONE;
@@ -143,6 +146,9 @@ public class CacheGroupContext {
     /** */
     private boolean qryEnabled;
 
+    /** */
+    private boolean mvccEnabled;
+
     /**
      * @param grpId Group ID.
      * @param ctx Context.
@@ -193,10 +199,26 @@ public class CacheGroupContext {
         log = ctx.kernalContext().log(getClass());
 
         caches = new ArrayList<>();
+
+        mvccEnabled = mvccEnabled(ctx.gridConfig(), ccfg);
+    }
+
+    /**
+     * @param cfg Ignite configuration.
+     * @param ccfg Cache configuration.
+     * @return {@code True} if mvcc is enabled for given cache.
+     */
+    public static boolean mvccEnabled(IgniteConfiguration cfg, CacheConfiguration ccfg) {
+        return cfg.isMvccEnabled() &&
+            ccfg.getCacheMode() != LOCAL &&
+            ccfg.getAtomicityMode() == TRANSACTIONAL;
     }
 
+    /**
+     * @return Mvcc flag.
+     */
     public boolean mvccEnabled() {
-        return ccfg.isMvccEnabled();
+        return mvccEnabled;
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
index 19bd05d..fb8416c 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/ClusterCachesInfo.java
@@ -237,9 +237,6 @@ class ClusterCachesInfo {
         CU.checkAttributeMismatch(log, rmtAttr.groupName(), rmt, "groupName", "Cache group
name",
             locAttr.groupName(), rmtAttr.groupName(), true);
 
-        CU.checkAttributeMismatch(log, rmtAttr.cacheName(), rmt, "mvccEnabled", "MVCC mode",
-            locAttr.mvccEnabled(), rmtAttr.mvccEnabled(), true);
-
         if (rmtAttr.cacheMode() != LOCAL) {
             CU.checkAttributeMismatch(log, rmtAttr.cacheName(), rmt, "interceptor", "Cache
Interceptor",
                 locAttr.interceptorClassName(), rmtAttr.interceptorClassName(), true);
@@ -1553,6 +1550,9 @@ class ClusterCachesInfo {
         CU.validateCacheGroupsAttributesMismatch(log, cfg, startCfg, "cacheMode", "Cache
mode",
             cfg.getCacheMode(), startCfg.getCacheMode(), true);
 
+        CU.validateCacheGroupsAttributesMismatch(log, cfg, startCfg, "mvccEnabled", "MVCC
mode",
+            CacheGroupContext.mvccEnabled(ctx.config(), cfg), CacheGroupContext.mvccEnabled(ctx.config(),
startCfg), true);
+
         CU.validateCacheGroupsAttributesMismatch(log, cfg, startCfg, "affinity", "Affinity
function",
             attr1.cacheAffinityClassName(), attr2.cacheAffinityClassName(), true);
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
index c1f03fa..d64ee8b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAttributes.java
@@ -329,13 +329,6 @@ public class GridCacheAttributes implements Serializable {
     }
 
     /**
-     * @return MVCC enabled flag.
-     */
-    public boolean mvccEnabled() {
-        return ccfg.isMvccEnabled();
-    }
-
-    /**
      * @param obj Object to get class of.
      * @return Class name or {@code null}.
      */

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
index ffe214e..c20b0b4 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheContext.java
@@ -2062,7 +2062,7 @@ public class GridCacheContext<K, V> implements Externalizable
{
      * @return {@code True} if mvcc is enabled for cache.
      */
     public boolean mvccEnabled() {
-        return cacheCfg.isMvccEnabled();
+        return grp.mvccEnabled();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
----------------------------------------------------------------------
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
index 07d09a5..a13a965 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java
@@ -465,16 +465,6 @@ public class GridCacheProcessor extends GridProcessorAdapter {
 
         ctx.igfsHelper().validateCacheConfiguration(cc);
 
-        if (cc.getAtomicityMode() == ATOMIC) {
-            assertParameter(cc.getTransactionManagerLookupClassName() == null,
-                "transaction manager can not be used with ATOMIC cache");
-
-            assertParameter(!cc.isMvccEnabled(), "MVCC can not used with ATOMIC cache");
-        }
-
-        if (cc.getCacheMode() == LOCAL)
-            assertParameter(!cc.isMvccEnabled(), "MVCC can not used with LOCAL cache");
-
         if (cc.getEvictionPolicy() != null && !cc.isOnheapCacheEnabled())
             throw new IgniteCheckedException("Onheap cache must be enabled if eviction policy
is configured [cacheName="
                 + U.maskName(cc.getName()) + "]");
@@ -1131,8 +1121,7 @@ public class GridCacheProcessor extends GridProcessorAdapter {
                 (cfg.getGroupName() != null ? ", group=" + cfg.getGroupName() : "") +
                 ", memoryPolicyName=" + memPlcName +
                 ", mode=" + cfg.getCacheMode() +
-                ", atomicity=" + cfg.getAtomicityMode() +
-                ", mvcc=" + cfg.isMvccEnabled() + ']');
+                ", atomicity=" + cfg.getAtomicityMode() + ']');
         }
     }
 

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsConfigurationValidationTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsConfigurationValidationTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsConfigurationValidationTest.java
new file mode 100644
index 0000000..250f641
--- /dev/null
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsConfigurationValidationTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+package org.apache.ignite.internal.processors.cache.mvcc;
+
+import java.util.concurrent.Callable;
+import javax.cache.CacheException;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder;
+import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest;
+
+import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+
+/**
+ *
+ */
+public class CacheMvccTransactionsConfigurationValidationTest extends GridCommonAbstractTest
{
+    /** */
+    private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true);
+
+    /** {@inheritDoc} */
+    @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception
{
+        IgniteConfiguration cfg = super.getConfiguration(gridName);
+
+        cfg.setMvccEnabled(true);
+
+        ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
+
+        return cfg;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void afterTest() throws Exception {
+        stopAllGrids();
+
+        super.afterTest();
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccModeMismatchForGroup1() throws Exception {
+        final Ignite node = startGrid(0);
+
+        node.createCache(new CacheConfiguration("cache1").setGroupName("grp1").setAtomicityMode(ATOMIC));
+
+        GridTestUtils.assertThrows(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                node.createCache(new CacheConfiguration("cache2").setGroupName("grp1").setAtomicityMode(TRANSACTIONAL));
+
+                return null;
+            }
+        }, CacheException.class, null);
+
+        node.createCache(new CacheConfiguration("cache2").setGroupName("grp1").setAtomicityMode(ATOMIC));
+    }
+
+    /**
+     * @throws Exception If failed.
+     */
+    public void testMvccModeMismatchForGroup2() throws Exception {
+        final Ignite node = startGrid(0);
+
+        node.createCache(new CacheConfiguration("cache1").setGroupName("grp1").setAtomicityMode(TRANSACTIONAL));
+
+        GridTestUtils.assertThrows(log, new Callable<Void>() {
+            @Override public Void call() throws Exception {
+                node.createCache(new CacheConfiguration("cache2").setGroupName("grp1").setAtomicityMode(ATOMIC));
+
+                return null;
+            }
+        }, CacheException.class, null);
+
+        node.createCache(new CacheConfiguration("cache2").setGroupName("grp1").setAtomicityMode(TRANSACTIONAL));
+    }
+}

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
----------------------------------------------------------------------
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
index 11980a9..28511cf 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/mvcc/CacheMvccTransactionsTest.java
@@ -52,7 +52,6 @@ import org.apache.ignite.internal.util.lang.GridInClosure3;
 import org.apache.ignite.internal.util.typedef.CI1;
 import org.apache.ignite.internal.util.typedef.F;
 import org.apache.ignite.internal.util.typedef.G;
-import org.apache.ignite.internal.util.typedef.PA;
 import org.apache.ignite.internal.util.typedef.internal.S;
 import org.apache.ignite.internal.util.typedef.internal.U;
 import org.apache.ignite.lang.IgniteBiPredicate;
@@ -75,6 +74,7 @@ import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_REA
 
 /**
  * TODO IGNITE-3478: extend tests to use single/mutiple nodes, all tx types.
+ * TODO IGNITE-3478: test with cache groups.
  */
 @SuppressWarnings("unchecked")
 public class CacheMvccTransactionsTest extends GridCommonAbstractTest {
@@ -100,6 +100,8 @@ public class CacheMvccTransactionsTest extends GridCommonAbstractTest
{
     @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception
{
         IgniteConfiguration cfg = super.getConfiguration(gridName);
 
+        cfg.setMvccEnabled(true);
+
         ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(IP_FINDER);
 
         if (testSpi)
@@ -1732,7 +1734,6 @@ public class CacheMvccTransactionsTest extends GridCommonAbstractTest
{
         ccfg.setCacheMode(cacheMode);
         ccfg.setAtomicityMode(TRANSACTIONAL);
         ccfg.setWriteSynchronizationMode(syncMode);
-        ccfg.setMvccEnabled(true);
         ccfg.setAffinity(new RendezvousAffinityFunction(false, parts));
 
         if (cacheMode == PARTITIONED)

http://git-wip-us.apache.org/repos/asf/ignite/blob/3d161614/modules/yardstick/src/main/java/org/apache/ignite/yardstick/IgniteNode.java
----------------------------------------------------------------------
diff --git a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/IgniteNode.java b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/IgniteNode.java
index b1160de..a9643ef 100644
--- a/modules/yardstick/src/main/java/org/apache/ignite/yardstick/IgniteNode.java
+++ b/modules/yardstick/src/main/java/org/apache/ignite/yardstick/IgniteNode.java
@@ -98,6 +98,8 @@ public class IgniteNode implements BenchmarkServer {
 
         CacheConfiguration[] ccfgs = c.getCacheConfiguration();
 
+        c.setMvccEnabled(args.mvccEnabled());
+
         if (ccfgs != null) {
             for (CacheConfiguration cc : ccfgs) {
                 // IgniteNode can not run in CLIENT_ONLY mode,
@@ -143,9 +145,7 @@ public class IgniteNode implements BenchmarkServer {
                 if (args.mvccEnabled()) {
                     if (cc.getAtomicityMode() == CacheAtomicityMode.TRANSACTIONAL &&
                         cc.getCacheMode() != CacheMode.LOCAL)
-                        cc.setMvccEnabled(true);
-
-                    cc.setNodeFilter(new TmpMvccNodeFilter());
+                        cc.setNodeFilter(new TmpMvccNodeFilter());
                 }
 
                 BenchmarkUtils.println(cfg, "Cache configured with the following parameters:
" + cc);


Mime
View raw message