Linkit icon indicating copy to clipboard operation
Linkit copied to clipboard

Synchronised Objects / Add a SyncInstanceCreator implementation that replaces the source object by it's synchronised version

Open Override-6 opened this issue 2 years ago • 0 comments

Summary

Create a SyncInstanceCreator that can replace an object directly in the memory, in order to Enhance the injection of a synchronised object by replacing the source object by it's synchronised version.

Goals

  • Ease the control of a program by injecting sychronised object more easily
  • Deal with limitations of the current SyncInstanceCreator implementations

Motivations

Current implementations and their limitations

There is two default ways to create a synchronised object using SynchronisedObjectCache#syncObject(int, SyncInstanceCreator )

  • Using a Content Paster :
val player: Player = new Player(new PlayerHealth, "John", "Cena")
val playerSyncs = cache.syncObject(id, ContentPaster(players))

The ContentPaster will basically paste all the fields of the player object to the synchronised object instance (playerSync). This will have for effect to possibly modify the player object when the playerSyncs will get modified, and vice-versa. However, as the player and playerSync are two different objects. And if a non-pure method is called (such as Player#setName) on one of those objects, the other one will still get the old name reference. Consequently, the two objects could get modified by the other in a pretty random and incomprehensible manner.

  • Using a constructor :
val syncFile: File = cache.syncObject(id, SyncConstructor("C:/any/file/text.txt"))

This is the most clean and safe way to create a synchronized object, However, this option does not allows the user to synchronize an already existing object. Of course, you have the ContentPaster, which support this, but, as said above, if the source object still used, some uncontrollable modifications would be received on the synchronized version, which is not acceptable.

The Replace implementation

Well, the concept of Replace(source) is not that hard to understand : Once you get the source object you desire to synchronise, using the Replace SyncInstanceCreator will replace the old object to its synchronized version. Here is an example :

val cache = manager.attachToCache(id, DefaultSynchronizedObjectCache)
val source: Player = list.get(winnerIndex)

assert(source.getClass == classOf[Player]) // the object's class is Player
cache.syncObject(x, Replace(source))
assert(source.getClass != classOf[Player]) //The object's class is now the PlayerSync (and not directly Player)

Complications

As the Object Layout and memory management is not part of the Oracle's specifications, each JVM have a different way to define it's object layout. This way, it is not possible to define a static code that would work on every JVMs; the "Write once, Run everywhere" feature of java will not be usable for the Replace implementation. Some native code would certainly be necessary for this task, but i've personally tried to write some native code, and i did not found a way to get an object's address. For the Hotspot & OpenJDK implementations, there is the JOL library that can do this, but it's using Unsafe, and this class will later be removed in next java versions.

Override-6 avatar Oct 08 '21 13:10 Override-6