Repository: mars-project/mars

Issue:
[BUG]Mutable tensor with identical properties should have different keys
**Describe the bug**

The key of mutable tensor, as well as its chunks, are generated based on the chunk's properties and the tensor's properties. When we create two mutable tensors with the same shape and dtype, we need to generate random keys for their chunks, as well as for the tensors.


Discussion:

Resolving patch:
diff --git a/mars/tensor/utils.py b/mars/tensor/utils.py
--- a/mars/tensor/utils.py
+++ b/mars/tensor/utils.py
@@ -21,6 +21,7 @@
 import inspect
 import itertools
 from functools import wraps
+import uuid
 
 import numpy as np
 try:
@@ -555,10 +556,10 @@ def create_fetch_tensor(chunk_size, shape, dtype, tensor_key=None, tensor_id=Non
                                                   itertools.product(*chunk_size_idxes),
                                                   chunk_keys):
         chunk = fetch_op.copy().reset_key().new_chunk(None, shape=chunk_shape, index=chunk_idx,
-                                                      _key=chunk_key)
+                                                      _key=chunk_key, hex=uuid.uuid4().hex)
         chunks.append(chunk)
     return fetch_op.copy().new_tensor(None, shape=shape, dtype=dtype, nsplits=chunk_size,
-                                      chunks=chunks, _key=tensor_key, _id=tensor_id)
+                                      chunks=chunks, _key=tensor_key, _id=tensor_id, hex=uuid.uuid4().hex)
 
 
 def create_mutable_tensor(name, chunk_size, shape, dtype, chunk_keys=None, chunk_eps=None):


Test patch:
diff --git a/mars/tests/test_mutable.py b/mars/tests/test_mutable.py
--- a/mars/tests/test_mutable.py
+++ b/mars/tests/test_mutable.py
@@ -376,8 +376,8 @@ def testWithGivenSession(session):
             session = cluster.session.as_default()
             testWithGivenSession(session)
 
-            with new_session('http://' + cluster._web_endpoint).as_default() as session:
-                testWithGivenSession(session)
+            with new_session('http://' + cluster._web_endpoint).as_default() as web_session:
+                testWithGivenSession(web_session)
 
     @mock.patch('webbrowser.open_new_tab', new=lambda *_, **__: True)
     def testMutableTensorFillValue(self):
@@ -417,8 +417,8 @@ def testWithGivenSession(session):
             session = cluster.session.as_default()
             testWithGivenSession(session)
 
-            with new_session('http://' + cluster._web_endpoint).as_default() as session:
-                testWithGivenSession(session)
+            with new_session('http://' + cluster._web_endpoint).as_default() as web_session:
+                testWithGivenSession(web_session)
 
     @mock.patch('webbrowser.open_new_tab', new=lambda *_, **__: True)
     def testMutableTensorString(self):
@@ -464,8 +464,40 @@ def testWithGivenSession(session):
             session = cluster.session.as_default()
             testWithGivenSession(session)
 
-            with new_session('http://' + cluster._web_endpoint).as_default():
-                testWithGivenSession(session)
+            with new_session('http://' + cluster._web_endpoint).as_default() as web_session:
+                testWithGivenSession(web_session)
+
+    @mock.patch('webbrowser.open_new_tab', new=lambda *_, **__: True)
+    def testIdenticalMutableTensor(self):
+        def testWithGivenSession(session):
+            from mars.tensor.core import mutable_tensor
+
+            # simple dtype.
+            mut1 = mutable_tensor("test1", (4, 5), dtype='int', chunk_size=3)
+            mut2 = mutable_tensor("test2", (4, 5), dtype='int', chunk_size=3)
+
+            mut1[:] = 111
+            mut2[:] = 222
+
+            arr1 = mut1.seal()
+            arr2 = mut2.seal()
+
+            expected1 = np.full((4, 5), 111, dtype='int')
+            expected2 = np.full((4, 5), 222, dtype='int')
+
+            np.testing.assert_array_equal(session.fetch(arr1), expected1)
+            np.testing.assert_array_equal(session.fetch(arr2), expected2)
+
+        with new_session().as_default() as session:
+            testWithGivenSession(session)
+
+        with new_cluster(scheduler_n_process=2, worker_n_process=2,
+                            shared_memory='20M', web=True) as cluster:
+            session = cluster.session.as_default()
+            testWithGivenSession(session)
+
+            with new_session('http://' + cluster._web_endpoint).as_default() as web_session:
+                testWithGivenSession(web_session)
 
     def assertRecordsEqual(self, records, expected):
         np.testing.assert_array_equal(records['index'], expected[:,0])