You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
*[4.5. Global Serialization](#45-global-serialization)
@@ -766,7 +767,7 @@ As an alternative to the existing serialization methods, Hazelcast offers portab
766
767
767
768
In order to support these features, a serialized `Portable` object contains meta information like the version and concrete location of the each field in the binary data. This way Hazelcast is able to navigate in the binary data and deserialize only the required field without actually deserializing the whole object which improves the query performance.
768
769
769
-
With multiversion support, you can have two members where each of them having different versions of the same object, and Hazelcast will store both meta information and use the correct one to serialize and deserialize portable objects depending on the member. This is very helpful when you are doing a rolling upgrade without shutting down the cluster.
770
+
With multiversion support, you can have two members each having different versions of the same object; Hazelcast stores both meta information and uses the correct one to serialize and deserialize portable objects depending on the member. This is very helpful when you are doing a rolling upgrade without shutting down the cluster.
770
771
771
772
Also note that portable serialization is totally language independent and is used as the binary protocol between Hazelcast server and clients.
772
773
@@ -776,14 +777,18 @@ A sample portable implementation of a `Foo` class looks like the following:
776
777
from hazelcast.serialization.api import Portable
777
778
778
779
classFoo(Portable):
780
+
781
+
CLASS_ID=1
782
+
FACTORY_ID=1
783
+
779
784
def__init__(self, foo=None):
780
785
self.foo = foo
781
786
782
787
defget_class_id(self):
783
-
return1
788
+
returnCLASS_ID
784
789
785
790
defget_factory_id(self):
786
-
return1
791
+
returnFACTORY_ID
787
792
788
793
defwrite_portable(self, writer):
789
794
writer.write_utf("foo", self.foo)
@@ -792,7 +797,7 @@ class Foo(Portable):
792
797
self.foo = reader.read_utf("foo")
793
798
```
794
799
795
-
> Note: For Portable to work in Python client, the class that inherits it should have default valued parameters in its `__init__` method so that an instance of that class can be created without passing any arguments to it.
800
+
> **NOTE: For Portable to work in Python client, the class that inherits it should have default valued parameters in its `__init__` method so that an instance of that class can be created without passing any arguments to it.**
796
801
797
802
Similar to `IdentifiedDataSerializable`, a `Portable` class must provide the `get_class_id()` and `get_factory_id()` methods. The factory dictionary will be used to create the `Portable` object given the class ID.
Note that the ID that is passed to the `SerializationConfig` is same as the factory ID that `Foo` class returns.
814
819
820
+
### 4.2.1. Versioning for Portable Serialization
821
+
822
+
More than one version of the same class may need to be serialized and deserialized. For example, a client may have an older version of a class and the member to which it is connected may have a newer version of the same class.
823
+
824
+
Portable serialization supports versioning. It is a global versioning, meaning that all portable classes that are serialized through a member get the globally configured portable version.
825
+
826
+
You can declare the version in the `hazelcast.xml` configuration file using the `portable-version` element, as shown below.
827
+
828
+
```xml
829
+
<hazelcast>
830
+
...
831
+
<serialization>
832
+
<portable-version>1</portable-version>
833
+
</serialization>
834
+
...
835
+
</hazelcast>
836
+
```
837
+
838
+
If you update the class by changing the type of one of the fields or by adding a new field, it is a good idea to upgrade the version of the class, rather than sticking to the global version specified in the `hazelcast.xml` file.
839
+
In the Python client, you can achieve this by simply adding the `get_class_version()` method to your class’s implementation of `Portable`, and setting the `CLASS_VERSION` to be different than the default global version.
840
+
841
+
> **NOTE: If you do not use the `get_class_version()` method in your `Portable` implementation, it will have the global version, by default.**
842
+
843
+
Here is an example implementation of creating a version 2 for the above Foo class:
844
+
845
+
```python
846
+
from hazelcast.serialization.api import Portable
847
+
848
+
classFoo(Portable):
849
+
850
+
CLASS_ID=1
851
+
FACTORY_ID=1
852
+
CLASS_VERSION=2
853
+
854
+
def__init__(self, foo=None, foo2=None):
855
+
self.foo = foo
856
+
self.foo2 = foo2
857
+
858
+
defget_class_id(self):
859
+
returnCLASS_ID
860
+
861
+
defget_factory_id(self):
862
+
returnFACTORY_ID
863
+
864
+
defget_class_version(self):
865
+
returnCLASS_VERSION
866
+
867
+
defwrite_portable(self, writer):
868
+
writer.write_utf("foo", self.foo)
869
+
writer.write_utf("foo2", self.foo2)
870
+
871
+
defread_portable(self, reader):
872
+
self.foo = reader.read_utf("foo")
873
+
self.foo2 = reader.read_utf("foo2")
874
+
```
875
+
876
+
You should consider the following when you perform versioning:
877
+
878
+
* It is important to change the version whenever an update is performed in the serialized fields of a class, for example by incrementing the version.
879
+
* If a client performs a Portable deserialization on a field and then that Portable is updated by removing that field on the cluster side, this may lead to problems such as an AttributeError being raised when an older version of the client tries to access the removed field.
880
+
* Portable serialization does not use reflection and hence, fields in the class and in the serialized content are not automatically mapped. Field renaming is a simpler process. Also, since the class ID is stored, renaming the Portable does not lead to problems.
881
+
* Types of fields need to be updated carefully. Hazelcast performs basic type upgradings, such as `int` to `float`.
882
+
883
+
#### Example Portable Versioning Scenarios:
884
+
885
+
Assume that a new client joins to the cluster with a class that has been modified and class's version has been upgraded due to this modification.
886
+
887
+
If you modified the class by adding a new field, the new client’s put operations include that new field. If this new client tries to get an object that was put from the older clients, it gets null for the newly added field.
888
+
889
+
If you modified the class by removing a field, the old clients get null for the objects that are put by the new client.
890
+
891
+
If you modified the class by changing the type of a field to an incompatible type (such as from `int` to `String`), a `TypeError` (wrapped as `HazelcastSerializationError`) is generated as the client tries accessing an object with the older version of the class. The same applies if a client with the old version tries to access a new version object.
892
+
893
+
If you did not modify a class at all, it works as usual.
894
+
815
895
## 4.3. Custom Serialization
816
896
817
897
Hazelcast lets you plug a custom serializer to be used for serialization of objects.
0 commit comments