blob: 83f84917c9ebb6f42a7b48111b0e16d344a351ff [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -08003 * Copyright (c) 2013-2017, Regents of the University of California.
Alexander Afanasyevdfe58192013-01-17 17:34:04 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Alexander Afanasyevdfe58192013-01-17 17:34:04 -08006 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08007 * ChronoShare is free software: you can redistribute it and/or modify it under the terms
8 * of the GNU General Public License as published by the Free Software Foundation, either
9 * version 3 of the License, or (at your option) any later version.
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080010 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080011 * ChronoShare is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU General Public License for more details.
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080014 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -080015 * You should have received copies of the GNU General Public License along with
16 * ChronoShare, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * See AUTHORS.md for complete list of ChronoShare authors and contributors.
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080019 */
20
21#include "fetcher.h"
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080022#include "ccnx-pco.h"
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -080023#include "fetch-manager.h"
Alexander Afanasyev678f3502013-01-23 17:09:37 -080024#include "logging.h"
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -080025
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080026#include <boost/date_time/posix_time/posix_time.hpp>
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080027#include <boost/make_shared.hpp>
28#include <boost/ref.hpp>
29#include <boost/throw_exception.hpp>
30
Alexander Afanasyev1cf5c432017-01-13 23:22:15 -080031_LOG_INIT(Fetcher);
Alexander Afanasyev678f3502013-01-23 17:09:37 -080032
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080033using namespace boost;
34using namespace std;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070035using namespace Ndnx;
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080036
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080037Fetcher::Fetcher(Ccnx::CcnxWrapperPtr ccnx, ExecutorPtr executor,
38 const SegmentCallback& segmentCallback, const FinishCallback& finishCallback,
39 OnFetchCompleteCallback onFetchComplete, OnFetchFailedCallback onFetchFailed,
40 const Ccnx::Name& deviceName, const Ccnx::Name& name, int64_t minSeqNo,
41 int64_t maxSeqNo,
42 boost::posix_time::time_duration timeout /* = boost::posix_time::seconds (30)*/,
43 const Ccnx::Name& forwardingHint /* = Ccnx::Name ()*/)
44 : m_ccnx(ccnx)
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080045
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080046 , m_segmentCallback(segmentCallback)
47 , m_onFetchComplete(onFetchComplete)
48 , m_onFetchFailed(onFetchFailed)
49 , m_finishCallback(finishCallback)
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080050
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080051 , m_active(false)
52 , m_timedwait(false)
53 , m_name(name)
54 , m_deviceName(deviceName)
55 , m_forwardingHint(forwardingHint)
56 , m_maximumNoActivityPeriod(timeout)
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080057
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080058 , m_minSendSeqNo(minSeqNo - 1)
59 , m_maxInOrderRecvSeqNo(minSeqNo - 1)
60 , m_minSeqNo(minSeqNo)
61 , m_maxSeqNo(maxSeqNo)
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080062
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080063 , m_pipeline(6) // initial "congestion window"
64 , m_activePipeline(0)
65 , m_retryPause(0)
66 , m_nextScheduledRetry(date_time::second_clock<boost::posix_time::ptime>::universal_time())
67 , m_executor(executor) // must be 1
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080068{
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080069}
70
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080071Fetcher::~Fetcher()
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080072{
Alexander Afanasyevdfe58192013-01-17 17:34:04 -080073}
Alexander Afanasyev83531a42013-01-19 16:21:54 -080074
75void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080076Fetcher::RestartPipeline()
Alexander Afanasyev83531a42013-01-19 16:21:54 -080077{
78 m_active = true;
Alexander Afanasyev50547892013-01-19 22:03:45 -080079 m_minSendSeqNo = m_maxInOrderRecvSeqNo;
Alexander Afanasyev650ba282013-01-20 20:14:06 -080080 // cout << "Restart: " << m_minSendSeqNo << endl;
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080081 m_lastPositiveActivity = date_time::second_clock<boost::posix_time::ptime>::universal_time();
Alexander Afanasyev50547892013-01-19 22:03:45 -080082
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080083 m_executor->execute(bind(&Fetcher::FillPipeline, this));
Alexander Afanasyev50547892013-01-19 22:03:45 -080084}
85
86void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080087Fetcher::SetForwardingHint(const Ccnx::Name& forwardingHint)
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080088{
89 m_forwardingHint = forwardingHint;
90}
91
92void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080093Fetcher::FillPipeline()
Alexander Afanasyev50547892013-01-19 22:03:45 -080094{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080095 for (; m_minSendSeqNo < m_maxSeqNo && m_activePipeline < m_pipeline; m_minSendSeqNo++) {
96 unique_lock<mutex> lock(m_seqNoMutex);
Alexander Afanasyev2ec2c382013-01-29 20:09:00 -080097
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -080098 if (m_outOfOrderRecvSeqNo.find(m_minSendSeqNo + 1) != m_outOfOrderRecvSeqNo.end())
99 continue;
Alexander Afanasyev650ba282013-01-20 20:14:06 -0800100
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800101 if (m_inActivePipeline.find(m_minSendSeqNo + 1) != m_inActivePipeline.end())
102 continue;
Alexander Afanasyevcfd5dfc2013-01-28 22:21:31 -0800103
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800104 m_inActivePipeline.insert(m_minSendSeqNo + 1);
Alexander Afanasyevcfd5dfc2013-01-28 22:21:31 -0800105
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800106 _LOG_DEBUG(" >>> i " << Name(m_forwardingHint)(m_name) << ", seq = " << (m_minSendSeqNo + 1));
Alexander Afanasyev678f3502013-01-23 17:09:37 -0800107
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800108 // cout << ">>> " << m_minSendSeqNo+1 << endl;
109 m_ccnx->sendInterest(Name(m_forwardingHint)(m_name)(m_minSendSeqNo + 1),
110 Closure(bind(&Fetcher::OnData, this, m_minSendSeqNo + 1, _1, _2),
111 bind(&Fetcher::OnTimeout, this, m_minSendSeqNo + 1, _1, _2, _3)),
112 Selectors().interestLifetime(1)); // Alex: this lifetime should be changed to RTO
113 _LOG_DEBUG(" >>> i ok");
Alexander Afanasyev50547892013-01-19 22:03:45 -0800114
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800115 m_activePipeline++;
116 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800117}
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800118
119void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800120Fetcher::OnData(uint64_t seqno, const Ccnx::Name& name, PcoPtr data)
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800121{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800122 m_executor->execute(bind(&Fetcher::OnData_Execute, this, seqno, name, data));
Alexander Afanasyevddc283c2013-01-28 23:11:20 -0800123}
124
125void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800126Fetcher::OnData_Execute(uint64_t seqno, Ccnx::Name name, Ccnx::PcoPtr data)
Alexander Afanasyevddc283c2013-01-28 23:11:20 -0800127{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800128 _LOG_DEBUG(" <<< d " << name.getPartialName(0, name.size() - 1) << ", seq = " << seqno);
Alexander Afanasyevfc720362013-01-24 21:49:48 -0800129
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800130 if (m_forwardingHint == Name()) {
Zhenkai Zhud5d99be2013-03-13 19:15:56 -0700131 // TODO: check verified!!!!
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800132 if (true) {
133 if (!m_segmentCallback.empty()) {
134 m_segmentCallback(m_deviceName, m_name, seqno, data);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800135 }
Zhenkai Zhu5957c0d2013-02-08 13:47:52 -0800136 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800137 else {
Zhenkai Zhu5957c0d2013-02-08 13:47:52 -0800138 _LOG_ERROR("Can not verify signature content. Name = " << data->name());
139 // probably needs to do more in the future
140 }
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -0800141 // we don't have to tell FetchManager about this
142 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800143 else {
144 // in this case we don't care whether "data" is verified, in fact, we expect it is unverified
145 try {
146 PcoPtr pco = make_shared<ParsedContentObject>(*data->contentPtr());
Zhenkai Zhu79264a42013-02-07 21:49:42 -0800147
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800148 // we need to verify this pco and apply callback only when verified
149 // TODO: check verified !!!
150 if (true) {
151 if (!m_segmentCallback.empty()) {
152 m_segmentCallback(m_deviceName, m_name, seqno, pco);
Zhenkai Zhu5957c0d2013-02-08 13:47:52 -0800153 }
Alexander Afanasyev66f4c492013-01-20 23:32:50 -0800154 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800155 else {
156 _LOG_ERROR("Can not verify signature content. Name = " << pco->name());
157 // probably needs to do more in the future
158 }
Alexander Afanasyev66f4c492013-01-20 23:32:50 -0800159 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800160 catch (MisformedContentObjectException& e) {
161 cerr << "MisformedContentObjectException..." << endl;
162 // no idea what should do...
163 // let's ignore for now
164 }
165 }
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800166
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800167 m_activePipeline--;
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800168 m_lastPositiveActivity = date_time::second_clock<boost::posix_time::ptime>::universal_time();
Alexander Afanasyev50547892013-01-19 22:03:45 -0800169
Yingdi Yuf0b3de32013-07-11 12:59:00 -0700170 {
171 unique_lock<mutex> lock (m_pipelineMutex);
172 if(m_slowStart){
173 m_pipeline++;
174 if(m_pipeline == m_threshold)
175 m_slowStart = false;
176 }
177 else{
178 m_roundCount++;
179 _LOG_DEBUG ("roundCount: " << m_roundCount);
180 if(m_roundCount == m_pipeline){
181 m_pipeline++;
182 m_roundCount = 0;
183 }
184 }
185 }
186
187 _LOG_DEBUG ("slowStart: " << boolalpha << m_slowStart << " pipeline: " << m_pipeline << " threshold: " << m_threshold);
188
189
Alexander Afanasyev50547892013-01-19 22:03:45 -0800190 ////////////////////////////////////////////////////////////////////////////
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800191 unique_lock<mutex> lock(m_seqNoMutex);
Alexander Afanasyev2ec2c382013-01-29 20:09:00 -0800192
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800193 m_outOfOrderRecvSeqNo.insert(seqno);
194 m_inActivePipeline.erase(seqno);
195 _LOG_DEBUG("Total segments received: " << m_outOfOrderRecvSeqNo.size());
196 set<int64_t>::iterator inOrderSeqNo = m_outOfOrderRecvSeqNo.begin();
197 for (; inOrderSeqNo != m_outOfOrderRecvSeqNo.end(); inOrderSeqNo++) {
198 _LOG_TRACE("Checking " << *inOrderSeqNo << " and " << m_maxInOrderRecvSeqNo + 1);
199 if (*inOrderSeqNo == m_maxInOrderRecvSeqNo + 1) {
200 m_maxInOrderRecvSeqNo = *inOrderSeqNo;
Alexander Afanasyev50547892013-01-19 22:03:45 -0800201 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800202 else if (*inOrderSeqNo < m_maxInOrderRecvSeqNo + 1) // not possible anymore, but just in case
203 {
204 continue;
205 }
206 else
207 break;
208 }
209 m_outOfOrderRecvSeqNo.erase(m_outOfOrderRecvSeqNo.begin(), inOrderSeqNo);
Alexander Afanasyev50547892013-01-19 22:03:45 -0800210 ////////////////////////////////////////////////////////////////////////////
211
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800212 _LOG_TRACE("Max in order received: " << m_maxInOrderRecvSeqNo
213 << ", max seqNo to request: " << m_maxSeqNo);
Alexander Afanasyevcfd5dfc2013-01-28 22:21:31 -0800214
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800215 if (m_maxInOrderRecvSeqNo == m_maxSeqNo) {
216 _LOG_TRACE("Fetch finished: " << m_name);
217 m_active = false;
218 // invoke callback
219 if (!m_finishCallback.empty()) {
220 _LOG_TRACE("Notifying callback");
221 m_finishCallback(m_deviceName, m_name);
222 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800223
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800224 // tell FetchManager that we have finish our job
225 // m_onFetchComplete (*this);
226 // using executor, so we won't be deleted if there is scheduled FillPipeline call
227 if (!m_onFetchComplete.empty()) {
228 m_timedwait = true;
229 m_executor->execute(bind(m_onFetchComplete, ref(*this), m_deviceName, m_name));
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800230 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800231 }
232 else {
233 m_executor->execute(bind(&Fetcher::FillPipeline, this));
234 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800235}
236
Zhenkai Zhuff4fa8a2013-01-28 22:02:40 -0800237void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800238Fetcher::OnTimeout(uint64_t seqno, const Ccnx::Name& name, const Closure& closure, Selectors selectors)
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800239{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800240 _LOG_DEBUG(this << ", " << m_executor.get());
241 m_executor->execute(bind(&Fetcher::OnTimeout_Execute, this, seqno, name, closure, selectors));
Alexander Afanasyevddc283c2013-01-28 23:11:20 -0800242}
243
244void
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800245Fetcher::OnTimeout_Execute(uint64_t seqno, Ccnx::Name name, Ccnx::Closure closure,
246 Ccnx::Selectors selectors)
Alexander Afanasyevddc283c2013-01-28 23:11:20 -0800247{
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800248 _LOG_DEBUG(" <<< :( timeout " << name.getPartialName(0, name.size() - 1) << ", seq = " << seqno);
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800249
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800250 // cout << "Fetcher::OnTimeout: " << name << endl;
251 // cout << "Last: " << m_lastPositiveActivity << ", config: " << m_maximumNoActivityPeriod
252 // << ", now: " << date_time::second_clock<boost::posix_time::ptime>::universal_time()
253 // << ", oldest: " << (date_time::second_clock<boost::posix_time::ptime>::universal_time() - m_maximumNoActivityPeriod) << endl;
254
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800255 if (m_lastPositiveActivity < (date_time::second_clock<boost::posix_time::ptime>::universal_time() -
256 m_maximumNoActivityPeriod)) {
257 bool done = false;
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800258 {
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800259 unique_lock<mutex> lock(m_seqNoMutex);
260 m_inActivePipeline.erase(seqno);
261 m_activePipeline--;
Alexander Afanasyev2ec2c382013-01-29 20:09:00 -0800262
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800263 if (m_activePipeline == 0) {
264 done = true;
265 }
266 }
267
268 if (done) {
269 {
270 unique_lock<mutex> lock(m_seqNoMutex);
271 _LOG_DEBUG("Telling that fetch failed");
272 _LOG_DEBUG("Active pipeline size should be zero: " << m_inActivePipeline.size());
Alexander Afanasyev2ec2c382013-01-29 20:09:00 -0800273 }
274
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800275 m_active = false;
276 if (!m_onFetchFailed.empty()) {
277 m_onFetchFailed(ref(*this));
Yingdi Yuf0b3de32013-07-11 12:59:00 -0700278 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800279 // this is not valid anymore, but we still should be able finish work
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800280 }
Alexander Afanasyeveda3b7a2016-12-25 11:26:40 -0800281 }
282 else {
283 _LOG_DEBUG("Asking to reexpress seqno: " << seqno);
284 m_ccnx->sendInterest(name, closure, selectors);
285 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800286}