>We¹ve implemented our own userprefs osapi service (yes, we dumped the
>whole
>idea of sitting on top of appdata).  As I understand it the calls to our
>service will be asynchronous.  Recently Dan Dumont made some changes to
>the
>common container layer to support a callback for GET_PREFERENCES so that
>we
>didn¹t try to render the gadget before the GET had completed.
>
>I need some help understanding the SET side of things.  A gadget could call
>SET for each userpref in rapid succession.  It¹s possible 2 of these could
>be handled simultaneously at the service layer (it¹s not only possible, we
>are hitting it EVERYTIME with the horoscope gadget).  Thus it¹s possible we
>could get a constraint violation on the database side (we are creating a
>master record that references the userpref values).  Two values could try to
>create the master record simultaneously.  Even if we flattened that out and
>didn¹t do the master record, the gadget COULD still set the same value twice
>in rapid succession and we¹d run into the same problem.
>
>So, it the right solution to return a 409 (conflict) from the service and
>have our container userprefs layer retry?  

Huh -- while reading through your question and thinking through how I might 
solve it, I realized that I have this same exact problem in at least two 
places!  :-)

I think the way I'm planning to solve it is to introduce some intelligent 
synchronization.  So within Rave we have a method in our RegionWidgetService 
layer to save a RegionWidgetPreference which looks something like this:

        public RegionWidgetPreference saveRegionWidgetPreference(long 
regionWidgetId, RegionWidgetPreference preference) {
                //fetch the region widget from the database
                //pull the preferences out of it and add or update the 
preference we were passed
                //save the region widget with its updated preferences back to 
the database
        }

So I think my solution is going to look something like this:

        public RegionWidgetPreference saveRegionWidgetPreference(long 
regionWidgetId, RegionWidgetPreference preference) {
                //fetch a lock object for this RegionWidget instance using the 
regionWidgetId as a key (I'm looking at the java.util.concurrent.locks.Lock 
interface)
                //lock on the lock object
                //fetch the region widget from the database
                //pull the preferences out of it and add or update the 
preference we were passed
                //save the region widget with its updated preferences back to 
the database
                //release the lock on the lock object
        }

Fetching/releasing the lock will be delegated off to a generic LockService 
which will have synchronized methods for fetching/releasing the locks -- this 
way the only synchronization overhead that *all* threads will incur is 
fetching/releasing the locks -- and the only time two (or more) threads will 
need to wait for each others database operations is if they are trying to set 
preferences for the same RegionWidget instance.

I'll post a follow up when I have this implemented in Rave with pointers to the 
implementation for reference.

> And doesn¹t this same issue exist
>from gadgets who are calling appdata (or any osapi write service for that
>matter)?  Should our services be trying to prevent this or only reporting
>errors?  Is there some shindig construct that helps with this?

I think all the code in Shindig that manipulates persistent data ends up doing 
so by delegating the actual data manipulation work off to an implementation of 
one of their SPI interfaces -- so I think it would be up to the implementer of 
those interfaces to do something like what I've outlined above.

>Your help is appreciated.
>
>Thanks,
>Doug

Reply via email to