Ejemplo n.º 1
0
        /// <summary>
        /// Reads data using only header information. Can be used by ReadDictionary
        /// so it handles deleted content too.
        /// </summary>
        /// <param name="contentLocation">Location of the data item without /proxy</param>
        /// <param name="contentType">GetMime()</param>
        /// <param name="eTag">Version number</param>
        /// <param name="addEntryToSender">These are entries that the sender does not know about</param>
        /// <param name="getEntryFromSender">This function fills in a list of entries that need to be requested from the sender</param>
        private ResponseAction ReadDataStub(string contentLocation, string contentType, string eTag, 
            List<int> sentFromList, out DataHeader getEntryFromSender, out SendMemoryToPeer addEntryToSender)
        {
            ResponseAction success = ResponseAction.DoNotForward;
            ETag tag = ReadETag(eTag);

            DataEntry get = null;
            getEntryFromSender = null;
            addEntryToSender = null;

            // create a stub of the item
            DataEntry create = new DataEntry(contentLocation, tag, sentFromList);
            create.subscribed = keysToListen.IsSubscribed(contentLocation);
            create.SetMime(contentType);

            // manually erase the value (TODO, don't erase the value)
            // always default to singleton because we assume that a GET is required to complete the request
            if (create.type != Data.ValueType.Removed)
                create.value = DataMissing.Singleton;

            this.dataLock.EnterUpgradeableReadLock();
            try
            {
                if (this.data.ContainsKey(contentLocation))
                {
                    // update the version number of the stub
                    get = this.data[contentLocation];
                }
                else
                {
                    this.dataLock.EnterWriteLock();
                    try
                    {
                        this.data.Add(contentLocation, create);
                    }
                    finally { this.dataLock.ExitWriteLock(); }

                    if (create.subscribed && DataMissing.IsSingleton(create.value))
                    {
                        // we'll have to wait for the data to arrive on the wire
                        // actually get the data
                        getEntryFromSender = new DataHeader(contentLocation, tag, sentFromList);
                        success = ResponseAction.DoNotForward;
                    }
                    else
                    {
                        success = ResponseAction.ForwardToSuccessor;
                    }

                }
            }

            finally
            {
                this.dataLock.ExitUpgradeableReadLock();
            }

            if (get != null)
            {
                lock (get)
                {
                    if (create.subscribed)
                    {
                        ETagCompare compareResult = ETag.CompareETags(tag, get.GetETag());

                        if (compareResult == ETagCompare.FirstIsNewer ||
                            compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            getEntryFromSender = new DataHeader(create.key, create.GetETag(), sentFromList);
                            success = ResponseAction.DoNotForward;
                        }
                        else //if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            // i know about something newer than the sender, tell the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // well, predecessor already been handled above, so we only need to tell
                            // the others
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                    else
                    {
                        // not subscribed
                        // just record the fact that there is newer data on the wire; cannot resolve conflicts without being a subscriber
                        ETagCompare compareResult = ETag.CompareETags(create.GetETag(), get.GetETag());
                        if (compareResult == ETagCompare.FirstIsNewer || compareResult == ETagCompare.Same || compareResult == ETagCompare.Conflict)
                        {
                            get.lastOwnerID = create.lastOwnerID;
                            get.lastOwnerRevision = create.lastOwnerRevision;
                            get.value = DataMissing.Singleton;

                            if (compareResult != ETagCompare.Same)
                            {
                                get.senderPath = create.senderPath;

                                success = ResponseAction.ForwardToSuccessor;
                            }
                            else
                                success = ResponseAction.DoNotForward;
                        }
                        else // if (compareResult == ETagCompare.SecondIsNewer )
                        {
                            //// i know about something newer than the sender
                            //SendMemoryToPeer mem = new SendMemoryToPeer(get.key,sentFromList);
                            //ResponseHeadStub(HEAD, get.key, GetListOfThisLocalID(), 0, get.GetMime(), get.GetETag(), get.IsEmpty, mem.MemBuffer, false);
                            //addEntryToSender = mem;

                            // tell the others too (already told predecessor above)
                            success = ResponseAction.ForwardToAll;
                        }
                    }
                }
            }

            return success;
        }
Ejemplo n.º 2
0
        /// <summary>
        ///  reads all sorts of data types
        /// </summary>
        /// <param name="contentLocation">location of the data</param>
        /// <param name="eTag">latest version of data being read</param>
        /// <param name="contentType"></param>
        /// <param name="dataOnWire">data read</param>
        /// <returns></returns>
        private ResponseAction ReadData(string contentLocation, string eTag, string contentType, List<int> senders, byte[] dataOnWire)
        {
            ResponseAction success = ResponseAction.DoNotForward;
            ETag tag = ReadETag(eTag);

            // constitute object
            DataEntry create = new DataEntry(contentLocation, tag, senders);
            create.subscribed = this.keysToListen.IsSubscribed(contentLocation);
            create.ReadBytesUsingMime(contentType, dataOnWire);

            bool upgradeable = true;
            DataEntry get = null;

            this.dataLock.EnterUpgradeableReadLock();
            try
            {
                if (this.data.ContainsKey(contentLocation))
                {
                    // update exisitng entry
                    get = this.data[contentLocation];
                }

                if (get == null)
                {
                    this.dataLock.EnterWriteLock();
                    try
                    {
                        // don't save the value if not subscribed
                        if (!create.subscribed)
                        {
                            create.value = DataMissing.Singleton;
                        }

                        this.data.Add(contentLocation, create);
                    }
                    finally
                    {
                        this.dataLock.ExitWriteLock();
                        this.dataLock.ExitUpgradeableReadLock();
                        upgradeable = false;
                    }

                    if (create.subscribed)
                    {
                        // notify API user
                        this.controller.Notified(new NotificationEventArgs(create, contentLocation, NotificationReason.Add, null));
                    }

                    // never seen before, thus tell others
                    success = ResponseAction.ForwardToSuccessor;
                }
            }
            finally
            {
                if (upgradeable)
                    this.dataLock.ExitUpgradeableReadLock();
            }

            if (get != null)
            {
                object oldValue = null;

                lock (get)
                {
                    if (create.subscribed)
                    {

                        ETagCompare compareResult = ETag.CompareETags(create.GetETag(), get.GetETag());
                        if (compareResult == ETagCompare.FirstIsNewer || compareResult == ETagCompare.Conflict || compareResult == ETagCompare.Same)
                        {
                            oldValue = get.value;

                            if (compareResult == ETagCompare.Conflict)
                            {
                                success = ResponseAction.ForwardToAll;

                                // increment the revision and take ownership
                                create.lastOwnerID = this.local_uid;
                                create.lastOwnerRevision = IncrementRevisionRandomizer(create.lastOwnerRevision);
                            }
                            else if (DataMissing.IsSingleton(oldValue))
                            {
                                success = ResponseAction.ForwardToSuccessor;
                            }
                            else if (compareResult == ETagCompare.Same)
                            {
                                success = ResponseAction.DoNotForward;
                            }
                            else//first is newer
                            {
                                success = ResponseAction.ForwardToSuccessor;
                            }

                            get.lastOwnerID = create.lastOwnerID;
                            get.lastOwnerRevision = create.lastOwnerRevision;
                            get.type = create.type;
                            get.value = create.value;

                        }
                        else // SecondIsNewer
                        {
                            // return this data to the sender
                            success = ResponseAction.ForwardToAll;
                        }

                    }
                    else
                    {
                        ETagCompare compareResult = ETag.CompareETags(create.GetETag(), get.GetETag());

                        if (compareResult == ETagCompare.FirstIsNewer || compareResult == ETagCompare.Conflict || compareResult == ETagCompare.Same)
                        {
                            if (compareResult == ETagCompare.Conflict)
                            {
                                success = ResponseAction.ForwardToAll;
                            }
                            else if (compareResult == ETagCompare.Same)
                            {
                                success = ResponseAction.DoNotForward;
                            }
                            else//first is newer
                            {
                                success = ResponseAction.ForwardToSuccessor;
                            }

                            if (compareResult != ETagCompare.Same)
                            {
                                get.lastOwnerID = create.lastOwnerID;
                                get.lastOwnerRevision = create.lastOwnerRevision;
                                get.type = create.type;
                                get.value = DataMissing.Singleton;
                                get.senderPath = create.senderPath;
                            }

                            System.Diagnostics.Debug.Assert(get.type != Data.ValueType.Removed);
                        }
                        else // second is newer
                        {
                            // return this data to the sender
                            success = ResponseAction.ForwardToAll;
                        }

                    }
                }//lock

                // notify API user
                if (success != ResponseAction.DoNotForward && get.subscribed && !DataMissing.IsSingleton(get.value))
                {
                    get.senderPath = create.senderPath;

                    this.controller.Notified(new NotificationEventArgs(get,contentLocation, NotificationReason.Change, oldValue));
                }

            } // else if

            return success;
        }