int IMessageController.PullFromPeer(DataHeader header) { if (this.IsAlive) { return(CastTargetController.PullFromPeer(header)); } else { return(0); } }
/// <summary> /// Removes a previous request based on its contentLocation and old version requested. /// </summary> /// <param name="request"></param> /// <returns>true if the request is removed, false otherwise</returns> public bool RemoveOldRequest(DataHeader request) { lock (this.receiveEntries) { if (receiveEntries.ContainsKey(request.key)) { DataHeader h = receiveEntries[request.key]; ETagCompare result = ETag.CompareETags(h.GetETag(), request.GetETag()); if (result == ETagCompare.SecondIsNewer || result == ETagCompare.Conflict) { // another version of the tag arrived, pull this request and have the new data requested this.receiveEntries.Remove(request.key); return true; } } } // this request is the newest return false; }
private void WriteSimpleGetRequest(MemoryStream stream, DataHeader request) { StreamWriter writer = new StreamWriter(stream, Encoding.ASCII); writer.NewLine = NEWLINE; writer.WriteLine("{0} {1} HTTP/1.1" , GET, request.key); writer.WriteLine("P2P-Sender-List: " + GetStringOf(request.sentFrom)); writer.WriteLine(SPECIAL_HEADER + ": " + this.local_uid); writer.WriteLine(); writer.Flush(); }
/// <summary> /// Adds a request to get data from the remote side. /// Call RemoveOldRequest() before this method. /// </summary> /// <param name="h"></param> public void AddRequest(DataHeader h) { lock (this.receiveEntries) { this.receiveEntries.Add(h.key, h); } lock(this.sendQueue) { this.sendQueue.Enqueue(h.key); } }
/// <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; }
private void HandleReadPush(string contentLocation, string contentType, string eTag, List<int> senders, int lastSender, List<int> responsePath) { ETag tag = ReadETag(eTag); if (contentLocation == DATA_NAMESPACE) { //// tell others that a new dictionary entered //// add to wire to send out //SendMemory sendMsg = new SendMemory(senders); //ResponseDictionary(verb, sendMsg.MemBuffer, senders, false); //controller.BroadcastToWire(sendMsg); // don't forward message because the GET method call will do it // let me update my model first by // requesting to pull data from the other side // before sending out a HEAD DataHeader hdr = new DataHeader(contentLocation, tag, lastSender); controller.PullFromPeer(hdr); } else { if (contentLocation.StartsWith(PROXY_PREFIX + "/")) { // this is a pushed message from a proxy request // so I should subscribe to the key contentLocation = contentLocation.Substring(PROXYPREFIX_REMOVE); throw new NotImplementedException(); } DataHeader getEntryFromSender; SendMemoryToPeer addEntryToSender; ResponseAction action = ReadDataStub(contentLocation, contentType, eTag, new List<int>(senders), out getEntryFromSender, out addEntryToSender); if (action == ResponseAction.ForwardToAll) { senders.Clear(); } if (action != ResponseAction.DoNotForward) { // forward a HEAD message (because we didn't do it when we got a 200/HEAD notification) DataEntry get = P2PDictionary.GetEntry(this.data, this.dataLock, contentLocation); System.Diagnostics.Debug.Assert(get != null); senders.Add(this.local_uid); SendBroadcastMemory sendMsg = new SendBroadcastMemory(contentLocation, senders); WriteMethodPush(contentLocation, senders, responsePath, 0, get.GetMime(), get.GetETag(), get.IsDeleted, false, sendMsg.MemBuffer); controller.BroadcastToWire(sendMsg); } if (getEntryFromSender != null) { // and get data from the caller controller.PullFromPeer(getEntryFromSender); } if (addEntryToSender != null) { // send any updates to the peer controller.SendToPeer(addEntryToSender); } } }
int IMessageController.PullFromPeer(DataHeader header) { if (this.IsAlive) return CastTargetController.PullFromPeer(header); else return 0; }