wiki:sqsync

SqSync

This framework enables applications to make use of shared objects in a distributed system with optimistic updates. It is well-suited for graphical user interfaces that rely on fast updates (< 200 ms).

How to Install

Environment
4.1, 4.2 Trunk
4.0.2 (Win)
not supported
Sources
ConfigurationOfSqSync
SqSync
SqSync
SY-AddressBook (optional)
SY-ProjectAnalyzation (optional)
Method Wrappers?
Signals
Widgets (optional)
ProcessLocalStorage
Misc
SqSync@SqueakSource

If you are on a recent 4.2 or Trunk image, you can use the Metacello configuration:

((Installer mc http: 'http://www.hpi.uni-potsdam.de/hirschfeld/squeaksource/')
	project: 'MetacelloRepository') install: 'ConfigurationOfSqSync'.
ConfigurationOfSqSync load.

If you cannot use Metacello, or prefer to install manually, just load the SqSync package from the Monticello HTTP repository.

The package Widgets is needed only for morphic controls and icons for the example application SyAddressBook2 which can be found in SY-AddressBook package.

Signals are used to provide a synchronization mechanism across process borders, i.e., while using multiple clients and servers in one Squeak image.

The SqSync package contains several sub-packages:

  • SqSync-Shared ... shared command objects and exceptions as well as the network protocol processing classes
  • SqSync-Client ... client-specific classes
  • SqSync-Server ... server-specific classes
  • SqSync-Repository ... shared model repository stuff
  • SqSync-Repository-Inception ... everything you need to intercept method calls
  • SqSync-Tools ... some customized versions of present classes
  • SqSync-Tests ... tests =)
  • SqSync-Tests-Model ... example model used in the tests
  • SqSync-Tests-Support ... mocks

How to Use

Custom Domain Model

Create your own domain model via inheritance from SqEntity. That domain model code has to be replicated to all clients and the server by yourself.

Model Restrictions

Do not use lazy initialization.

Make use of the #initialize method in each model to set initial values. Failure to do so will result in each setter being recognized as changing the model and those changes will be replicated to other clients.

"Wrong."
SyPerson>>friends
   ^ friends ifNil: [friends := OrderedCollection new]

"Correct."
SyPerson>>initialize
   super initialize.
   friends := OrderedCollection new.

SyPerson>>friends
   ^ friends

Force method replication of non-SqSync objects with <replicate> pragma.

If you use other objects apart from your domain models in your application, you will need to tell SqSync explicitely which method call results in an object change and therefore needs to be replicated.

SyPerson>>addFriend: aPerson
   <replicate>
   self friends add: aPerson. "friends is OrderedCollection"

Do not initialize an object with SqSync subtypes from within.

Call this a bug, but a client needs to set these objects from the outside so that proper method wrappers can be installed and the object's method calls will be replicated correctly.

"Wrong."
SyPerson>>initialize
   super initialize.
   address := SyAddress new.

"Correct."
| myPerson |
myPerson := SyPerson new.
myPerson address: SyAddress new.

Creating the new SyAddress instance during the initilization of SyPerson does not register the address on the server as only the object creation (i.e., SyPerson new) is replicated to all clients.

Emitting signals in a model do not replicate resulting method calls.

This advice only applies if you work with Signals in your model. As model changes are processed in the Squeak UI process, a connection to a resulting model change is not replicated because everything is threated as one call.

SyPerson>>givenNameChanged: newName
   "Signal."
   self emit.

SyPerson>>givenName: aString
   givenName: aString.
   self givenNameChanged: aString.

...

self connect: myPerson signal: #givenNameChanged: toSelector: #updateTimeStamp.

...

MyObject>>updateTimeStamp
   myPerson timestamp: TimeStamp now.

This is only a problem if used like in the example above. Every client sets his own timestamp in the model. There is not one client that sets the timestamp and every other clients gets this timestamp replicate. So pay attention to this.

Server Startup & Shutdown

To start a server that runs on port 22701 open a workspace and do:

myServer := SyServer new start.

To shutdown the server, just call #stop. A server instance can and should be re-used as it holds the complete repository with all instance of the domain.

Client Connection

In any application you need an SyClient object that connects to a server and so opens a TCP connection:

myClient := SyClient new
   connectToHostNamed: 'localhost' port: 22701.
"or connectToHostNamed: '127.0.0.1' port: 22701."

You close the connection with #disconnect.

Creating Objects

If your repository is empty, you will get now objects from the server. At first, you need to register and define a new root object:

myClient repository rootObject: PersonList new.

From this point on, you should work with your root object. If you already did register a root object, just get it after the client connected:

personList := myClient repository rootObject.

Further objects should only be added via the root object. Therefore the root object needs an interface to add other objects like this:

personList addPerson: Person new.

The new instance of Person will be registered and is now part of the shared domain graph and visible for other clients.

However, it is possible to register and access objects in the global object list:

"Fetch the list of all registered objects."
allDomainObjects := myClient repository all.

"Register any object of type SqEntity."
myServer repository register: Person new.

Weak References

To allow garbage collection of shared objects, clients need to refrain from keeping strong references to objects that are reachable from the root object. You should never do this:

"Forbidden."
myClient repository register: Person new.

Only the server keeps strong references to all objects.

How to Extend

Internal documentation. Show models, explain the architecture. Do anything that may help a new developer to extend this project.

Acknowledgments

To date, the following people contributed to this project:

  • Robert Krahn
  • Stefan Richter
  • Christopher Schuster
  • Bastian Steinert
  • Marcel Taeumel
Last modified 7 years ago Last modified on 12/06/2010 10:25:21 AM