blob: a6176c0cc647b292e85077bc2b869ef6f8ccb8fc [file] [log] [blame]
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
3 * Copyright (c) 2013-2016, Regents of the University of California.
Alexander Afanasyev8811b352013-01-02 12:51:15 -08004 *
Alexander Afanasyevfa2f6622016-12-25 12:28:00 -08005 * This file is part of ChronoShare, a decentralized file sharing application over NDN.
Alexander Afanasyev8811b352013-01-02 12:51:15 -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 Afanasyev8811b352013-01-02 12:51:15 -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 Afanasyev8811b352013-01-02 12:51:15 -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 Afanasyev8811b352013-01-02 12:51:15 -080019 */
20
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080021#include "fetch-manager.hpp"
Alexander Afanasyev49a18522013-01-18 17:49:04 -080022#include <boost/make_shared.hpp>
23#include <boost/ref.hpp>
24#include <boost/throw_exception.hpp>
Zhenkai Zhu354d46d2013-02-06 13:49:48 -080025#include <boost/lexical_cast.hpp>
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080026
Alexander Afanasyevf4cde4e2016-12-25 13:42:57 -080027#include "simple-interval-generator.hpp"
28#include "logging.hpp"
Alexander Afanasyevfc720362013-01-24 21:49:48 -080029
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -080030INIT_LOGGER ("FetchManager");
Alexander Afanasyev49a18522013-01-18 17:49:04 -080031
32using namespace boost;
33using namespace std;
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070034using namespace Ndnx;
Alexander Afanasyev49a18522013-01-18 17:49:04 -080035
Alexander Afanasyev83531a42013-01-19 16:21:54 -080036//The disposer object function
37struct fetcher_disposer { void operator() (Fetcher *delete_this) { delete delete_this; } };
38
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080039static const string SCHEDULE_FETCHES_TAG = "ScheduleFetches";
40
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070041FetchManager::FetchManager (Ndnx::NdnxWrapperPtr ndnx,
Alexander Afanasyev473346f2013-02-07 14:14:45 -080042 const Mapping &mapping,
43 const Name &broadcastForwardingHint,
44 uint32_t parallelFetches, // = 3
45 const SegmentCallback &defaultSegmentCallback,
46 const FinishCallback &defaultFinishCallback,
47 const FetchTaskDbPtr &taskDb
48 )
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070049 : m_ndnx (ndnx)
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080050 , m_mapping (mapping)
Alexander Afanasyev83531a42013-01-19 16:21:54 -080051 , m_maxParallelFetches (parallelFetches)
52 , m_currentParallelFetches (0)
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080053 , m_scheduler (new Scheduler)
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080054 , m_executor (new Executor(1))
Zhenkai Zhua0147382013-01-29 15:57:27 -080055 , m_defaultSegmentCallback(defaultSegmentCallback)
56 , m_defaultFinishCallback(defaultFinishCallback)
Zhenkai Zhuda686882013-01-29 22:32:24 -080057 , m_taskDb(taskDb)
Alexander Afanasyev473346f2013-02-07 14:14:45 -080058 , m_broadcastHint (broadcastForwardingHint)
Alexander Afanasyev8811b352013-01-02 12:51:15 -080059{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080060 m_scheduler->start ();
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080061 m_executor->start();
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080062
Alexander Afanasyev4aecad82013-01-31 15:27:08 -080063 m_scheduleFetchesTask = Scheduler::schedulePeriodicTask (m_scheduler,
64 make_shared<SimpleIntervalGenerator> (300), // no need to check to often. if needed, will be rescheduled
65 bind (&FetchManager::ScheduleFetches, this), SCHEDULE_FETCHES_TAG);
Zhenkai Zhuda686882013-01-29 22:32:24 -080066 // resume un-finished fetches if there is any
67 if (m_taskDb)
68 {
69 m_taskDb->foreachTask(bind(&FetchManager::Enqueue, this, _1, _2, _3, _4, _5));
70 }
Alexander Afanasyev49a18522013-01-18 17:49:04 -080071}
Alexander Afanasyeva199f972013-01-02 19:37:26 -080072
Alexander Afanasyev49a18522013-01-18 17:49:04 -080073FetchManager::~FetchManager ()
74{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080075 m_scheduler->shutdown ();
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080076 m_executor->shutdown();
77
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070078 m_ndnx.reset ();
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080079
Alexander Afanasyev83531a42013-01-19 16:21:54 -080080 m_fetchList.clear_and_dispose (fetcher_disposer ());
Alexander Afanasyev49a18522013-01-18 17:49:04 -080081}
Alexander Afanasyev8811b352013-01-02 12:51:15 -080082
Zhenkai Zhua0147382013-01-29 15:57:27 -080083// Enqueue using default callbacks
84void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070085FetchManager::Enqueue (const Ndnx::Name &deviceName, const Ndnx::Name &baseName,
Zhenkai Zhua0147382013-01-29 15:57:27 -080086 uint64_t minSeqNo, uint64_t maxSeqNo, int priority)
87{
88 Enqueue(deviceName, baseName, m_defaultSegmentCallback, m_defaultFinishCallback, minSeqNo, maxSeqNo, priority);
89}
90
Alexander Afanasyev49a18522013-01-18 17:49:04 -080091void
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -070092FetchManager::Enqueue (const Ndnx::Name &deviceName, const Ndnx::Name &baseName,
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080093 const SegmentCallback &segmentCallback, const FinishCallback &finishCallback,
94 uint64_t minSeqNo, uint64_t maxSeqNo, int priority/*PRIORITY_NORMAL*/)
Alexander Afanasyev49a18522013-01-18 17:49:04 -080095{
Zhenkai Zhu454bae22013-01-24 19:27:54 -080096 // Assumption for the following code is minSeqNo <= maxSeqNo
97 if (minSeqNo > maxSeqNo)
98 {
99 return;
100 }
101
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800102 // we may need to guarantee that LookupLocator will gives an answer and not throw exception...
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800103 Name forwardingHint;
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -0800104 forwardingHint = m_mapping (deviceName);
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800105
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800106 if (m_taskDb)
107 {
108 m_taskDb->addTask(deviceName, baseName, minSeqNo, maxSeqNo, priority);
109 }
Zhenkai Zhuda686882013-01-29 22:32:24 -0800110
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800111 unique_lock<mutex> lock (m_parellelFetchMutex);
112
113 _LOG_TRACE ("++++ Create fetcher: " << baseName);
Alexander Afanasyev1dd37ed2013-08-14 18:08:09 -0700114 Fetcher *fetcher = new Fetcher (m_ndnx,
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800115 m_executor,
116 segmentCallback,
117 finishCallback,
Zhenkai Zhuda686882013-01-29 22:32:24 -0800118 bind (&FetchManager::DidFetchComplete, this, _1, _2, _3),
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800119 bind (&FetchManager::DidNoDataTimeout, this, _1),
120 deviceName, baseName, minSeqNo, maxSeqNo,
121 boost::posix_time::seconds (30),
122 forwardingHint);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800123
124 switch (priority)
125 {
126 case PRIORITY_HIGH:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800127 _LOG_TRACE ("++++ Push front fetcher: " << fetcher->GetName ());
128 m_fetchList.push_front (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800129 break;
130
131 case PRIORITY_NORMAL:
132 default:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800133 _LOG_TRACE ("++++ Push back fetcher: " << fetcher->GetName ());
134 m_fetchList.push_back (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800135 break;
136 }
137
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800138 _LOG_DEBUG ("++++ Reschedule fetcher task");
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800139 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
140 // ScheduleFetches (); // will start a fetch if m_currentParallelFetches is less than max, otherwise does nothing
Alexander Afanasyev49a18522013-01-18 17:49:04 -0800141}
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800142
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800143void
144FetchManager::ScheduleFetches ()
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800145{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800146 unique_lock<mutex> lock (m_parellelFetchMutex);
147
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800148 boost::posix_time::ptime currentTime = date_time::second_clock<boost::posix_time::ptime>::universal_time ();
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800149 boost::posix_time::ptime nextSheduleCheck = currentTime + posix_time::seconds (300); // no reason to have anything, but just in case
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800150
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800151 for (FetchList::iterator item = m_fetchList.begin ();
152 m_currentParallelFetches < m_maxParallelFetches && item != m_fetchList.end ();
153 item++)
154 {
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800155 if (item->IsActive ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800156 {
157 _LOG_DEBUG ("Item is active");
158 continue;
159 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800160
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800161 if (item->IsTimedWait ())
162 {
163 _LOG_DEBUG ("Item is in timed-wait");
164 continue;
165 }
166
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800167 if (currentTime < item->GetNextScheduledRetry ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800168 {
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800169 if (item->GetNextScheduledRetry () < nextSheduleCheck)
170 nextSheduleCheck = item->GetNextScheduledRetry ();
171
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800172 _LOG_DEBUG ("Item is delayed");
173 continue;
174 }
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800175
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800176 _LOG_DEBUG ("Start fetching of " << item->GetName ());
177
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800178 m_currentParallelFetches ++;
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800179 _LOG_TRACE ("++++ RESTART PIPELINE: " << item->GetName ());
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800180 item->RestartPipeline ();
181 }
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800182
Alexander Afanasyeve10e5f22013-02-08 22:10:13 -0800183 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, (nextSheduleCheck - currentTime).total_seconds ());
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800184}
185
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800186void
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800187FetchManager::DidNoDataTimeout (Fetcher &fetcher)
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800188{
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800189 _LOG_DEBUG ("No data timeout for " << fetcher.GetName () << " with forwarding hint: " << fetcher.GetForwardingHint ());
190
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800191 {
192 unique_lock<mutex> lock (m_parellelFetchMutex);
193 m_currentParallelFetches --;
194 // no need to do anything with the m_fetchList
195 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800196
Alexander Afanasyev84894d32013-02-08 22:27:12 -0800197 if (fetcher.GetForwardingHint ().size () == 0)
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800198 {
Alexander Afanasyev84894d32013-02-08 22:27:12 -0800199 // will be tried initially and again after empty forwarding hint
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800200
201 /// @todo Handle potential exception
202 Name forwardingHint;
203 forwardingHint = m_mapping (fetcher.GetDeviceName ());
Alexander Afanasyev84894d32013-02-08 22:27:12 -0800204
205 if (forwardingHint.size () == 0)
206 {
207 // make sure that we will try broadcast forwarding hint eventually
208 fetcher.SetForwardingHint (m_broadcastHint);
209 }
210 else
211 {
212 fetcher.SetForwardingHint (forwardingHint);
213 }
214 }
215 else if (fetcher.GetForwardingHint () == m_broadcastHint)
216 {
217 // will be tried after broadcast forwarding hint
218 fetcher.SetForwardingHint (Name ("/"));
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800219 }
220 else
221 {
Alexander Afanasyev84894d32013-02-08 22:27:12 -0800222 // will be tried after normal forwarding hint
Alexander Afanasyev473346f2013-02-07 14:14:45 -0800223 fetcher.SetForwardingHint (m_broadcastHint);
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800224 }
225
226 double delay = fetcher.GetRetryPause ();
227 if (delay < 1) // first time
228 {
229 delay = 1;
230 }
231 else
232 {
233 delay = std::min (2*delay, 300.0); // 5 minutes max
234 }
235
236 fetcher.SetRetryPause (delay);
237 fetcher.SetNextScheduledRetry (date_time::second_clock<boost::posix_time::ptime>::universal_time () + posix_time::seconds (delay));
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800238
239 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800240}
241
242void
Zhenkai Zhuda686882013-01-29 22:32:24 -0800243FetchManager::DidFetchComplete (Fetcher &fetcher, const Name &deviceName, const Name &baseName)
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800244{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800245 {
246 unique_lock<mutex> lock (m_parellelFetchMutex);
247 m_currentParallelFetches --;
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800248
249 if (m_taskDb)
250 {
251 m_taskDb->deleteTask(deviceName, baseName);
252 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800253 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800254
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800255 // like TCP timed-wait
256 m_scheduler->scheduleOneTimeTask(m_scheduler, 10, boost::bind(&FetchManager::TimedWait, this, ref(fetcher)), boost::lexical_cast<string>(baseName));
257
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800258 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800259}
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800260
261void
262FetchManager::TimedWait (Fetcher &fetcher)
263{
264 unique_lock<mutex> lock (m_parellelFetchMutex);
265 _LOG_TRACE ("+++++ removing fetcher: " << fetcher.GetName ());
266 m_fetchList.erase_and_dispose (FetchList::s_iterator_to (fetcher), fetcher_disposer ());
267}