10 Replies Latest reply on Nov 25, 2008 8:44 PM by scotchfasterr

    Local Shared Objects and multiple SWFs: mutexes necessary?

    scotchfasterr
      I will have multiple SWFs on a single web page, each reading and writing the same SharedObject, which may be up to 100K in size. Will I need to create some sort of mutex scheme to ensure that one SWF isn't writing while another is reading, or do all SWFs on a page essentially run as a single-threaded application?
        • 1. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
          rtalton Level 4
          This may help:
          http://livedocs.adobe.com/flex/3/html/help.html?content=05B_Security_15.html

          I have never tried having multiple SWFs simultaneously write to the same shared object, but I imagine you'd get into problems doing that, just like with some database operations.

          The shared object does include a netStatus event which you could use examine the results of write operations.

          http://livedocs.adobe.com/flex/3/langref/index.html?flash/net/SharedObject.html&flash/net/ class-list.html
          • 2. Local Shared Objects and multiple SWFs: mutexes necessary?
            scotchfasterr Level 1
            Thanks for responding, although I'm not seeing the answer in the documentation.

            I'm not sure this is exactly analogous to a database operation, because there's no external software the FlashPlayer is interacting with. In theory, the FlashPlayer should be able to prevent collisions gracefully. In fact, I don't think there would be a problem here at all if:

            1) SharedObject.flush() is really, truly synchronous, as it appears, AND
            2) All SWFs on a page use cooperative multitasking instead of preemptive. That is, if one SWF calls SharedObject.flush(), no other SWFs will execute their instructions until the flush() has finished.

            Even if that weren't the case, and each SWF ran in its own FlashPlayer VM, Adobe could still manage this gracefully.

            I'm working on code to test this empirically, but I'd sure like to know that my code won't break in the future.

            Thanks!
            • 3. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
              rtalton Level 4
              1) I don't think a SharedObject.flush is synchronous.
              2) This sounds like a feature request!

              The netStatus event will tell you if a SWF's flush is pending (SharedObjectFlushStatus.PENDING):
              var status:String = sObj.flush();
              if(status == SharedObjectFlushStatus.PENDING){
              //Add listener to try a flush later:
              sObj.addEventListener(NetStatusEvent.NET_STATUS,flushStatusHandler);
              }

              Now you can check for NetStatusEvent.NET_STATUS.info.code for either:
              a) SharedObject.Flush.Failed OR
              b) SharedObject.Flush.Success



              You could then decide whether the flush was successful or not, and try again:

              private function flushStatusHandler(evt:NetStatusEvent):void{
              evt.target.removeEventListener(NetStatusEvent.NET_STATUS,flushStatusHandler);
              if(evt.info.code == "SharedObject.Flush.Failed"){
              //Shared object was NOT flushed successfully:
              Alert.show("You must allow local data storage in order to login.");
              }else if(evt.info.code == 'SharedObject.Flush.Success'){
              //The flush was successful, so continue:

              }
              }
              • 4. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                scotchfasterr Level 1
                >1) I don't think a SharedObject.flush is synchronous.

                I believe it is, as long as you're not attempting to write more data than the user has set for the Local Storage limit.
                http://livedocs.adobe.com/flex/3/langref/flash/net/SharedObject.html#flush()

                You'll note that flush is described this way: "Immediately writes a locally persistent shared object to a local file", and if it returns "SharedObjectFlushStatus.FLUSHED" that means that "The shared object has been successfully written to a file on the local disk". So I'd say that the normal operation of flush() is synchronous. However, the SharedObjectFlushStatus.PENDING state means that we've exceeded the limit set by the user, and are waiting for them to allow or disallow it. I believe (strongly) that that's the only case in which a netStatus event is sent.

                Do you read this differently?

                As far as multiple SWFs running as cooperative or preemptive multitasking processes, I'd really like to know the answer, but it probably doesn't matter. The more I read and think about this, the more it seems to me that Adobe has to prevent simultaneous reads and writes to a single Shared Object from taking place, as one use of it that I've read about is to share data between SWFs. For example:

                http://www.devarticles.com/c/a/Flash/Communication-and-Security-with-the-Flash-Communicati on-Server/1/
                • 5. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                  rtalton Level 4
                  Good point re: the PENDING status. I re-read this section of the help docs and tested it to verify.

                  Whether or not the flush is "synchronous" may be irrelevant. I think you can still manage different SWFs writing to the same SO.
                  Check out:
                  http://livedocs.adobe.com/flex/3/langref/index.html?flash/net/SharedObjectFlushStatus.html &flash/net/class-list.html

                  ..and read about the "FLUSHED" status code. I think you should check this whenever you flush the SO, then decide whether to retry or not if it failed. Shouldn't be too difficult as long as your SWFs are not trying to write to the SO too frequently-you shouldn't get a collision when writing.

                  As far as reading the SO while it is being written to...
                  I haven't tested this. But what I use in my app is to get an instance of the SO when starting up and read from that.
                  example:
                  [Bindable]
                  public var sObj:SharedObject;
                  So, I'm not actually reading from the SO on disk once it's in memory.
                  At this point, any other SWF could also have their own instance in memory, reading/writing with it, and then finally calling FLUSH.

                  Now, keeping the these SOs in synch may be an issue. But you'd have to "refresh" the SO before reading from it to get any updates.

                  Adobe's answer to this would be to use the REMOTE shared objects with Flash Media Server.

                  This should address your original concern regarding reading/writing to the SO from different SWFs.
                  Good luck!
                  • 6. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                    scotchfasterr Level 1
                    > ..and read about the "FLUSHED" status code. I think you should
                    > check this whenever you flush the SO, then decide whether to retry or
                    > not if it failed.

                    I don't believe you ever retry. Check out SharedObjectExample.as here:

                    http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/net/SharedObject.html

                    I believe it works this way. If SharedObject.flush() returns SharedObjectFlushStatus.FLUSHED, we're done. If it returns SharedObjectFlushStatus.PENDING, then the user is being prompted whether or not to increase the Local Storage size, and we get a NetStatusEvent to indicate whether the user allowed it or not. Finally, flush() can throw an error, which I believe it will do if the user has selected a low (or zero) size for Local Storage and selected "Do Not Ask Again".

                    >But you'd have to "refresh" the SO before reading from it to get any
                    >updates.

                    How do you do that?
                    • 7. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                      rtalton Level 4
                      Looks like you have a good grip on this whole SO thing now, and I've really benefited from a closer reading of the help docs, too.

                      I would still consider re-trying the FLUSH, under some circumstances. In my app, if a user cannot login, it's keeping a lot of functionality away from them. So I do give them a useful error message to try and get them through allowing local storage during a SharedObjectFlushStatus.PENDING. In this case, I agree with your statement about not retrying if they dis-allow local storage.

                      But in your circumstance, you might get an write collision when two SWFs are attempting a FLUSH operation simultaneously. Who knows what that error would be, but it would not be a NetStatusEvent. You could use a try-catch statement during any FLUSH, catch any error, and under THAT circumstance, set a timer to retry after a very short interval, maybe 250-500 ms. I would only attempt a retry IF I knew storage was NOT dis-allowed (which I already checked for when the app launches).

                      As far as refreshing the SO, what I meant by that was simply refetching the instance of the SO, like:
                      sObj = SharedObject.getLocal("custInfo");
                      ..as it may have been updated by another SWF, and I'd want the most current data.

                      Well, that's about all I've got. This has made me go back and completely re-do the login procedure in my app!

                      • 8. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                        scotchfasterr Level 1
                        If you're not already, you really need to test this by lowering the Local Storage and trying to write to the SO. The retry really sounds like bad mojo to me...you need to be careful not to harass the user.

                        I've written a test SWF that repeatedly reads and writes to a LSO, and created a web page containing many instances of the SWF. There do not appear to be any problems with collisions.

                        In my case, I don't think I can use a Remote Shared Object. At least, I don't think I can, because I'm using the Shared Object to maintain a "local cache" of data obtained from a database. Therefore, I think I'd need to use a unique name for the RSO for each individual computer, and even if I knew how to do this, I'd think it would create bandwidth issues - which is the problem I'm trying to solve. At least, that's my current understanding of RSOs. Do you understand this differently?

                        The one quirk I've encountered is that in order to read in a LSO properly after another instance has written to it, it's necessary to destroy the SharedObject (by removing all references to it) before reopening it - otherwise, you'll just get the last data that your instance wrote. Calling SharedObject.close() doesn't do it.
                        • 9. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                          rtalton Level 4
                          Sounds like you have the solution now. Good going! Now I know how to do this myself when the time comes.

                          Your "quirk" just sounds like expected behavior for an instance of an SO- I wouldn't expect it to contain any updated data after a flush operation from another SWF.

                          But instead of closing it and re-opening it, try:
                          sObj = SharedObject.getLocal("custInfo");
                          to re-instantiate it and get the latest data into it before performing any operations with it. No need to use close as it is only for remote objects, not local.
                          • 10. Re: Local Shared Objects and multiple SWFs: mutexes necessary?
                            scotchfasterr Level 1
                            Yeah, I still think there's something quirky here. Consider the attached code. If writeSharedObject() is called, and then another instance in the same domain writes a different value to mySO.data.test, readSharedObject() will still output "Hello world". The fix: add "mySO = null;" to the end of both functions, or use local variables.

                            Obviously, this code is simplified for illustration purposes. Hope this is helpful for someone else.