blob: af72e0848914800da8ca11b202801e4e550cec18 [file] [log] [blame]
Alexander Afanasyev8811b352013-01-02 12:51:15 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2012 University of California, Los Angeles
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 *
18 * Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
19 * Zhenkai Zhu <zhenkai@cs.ucla.edu>
20 */
21
Alexander Afanasyev49a18522013-01-18 17:49:04 -080022#include "fetch-manager.h"
23#include <boost/make_shared.hpp>
24#include <boost/ref.hpp>
25#include <boost/throw_exception.hpp>
Zhenkai Zhu354d46d2013-02-06 13:49:48 -080026#include <boost/lexical_cast.hpp>
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080027
28#include "simple-interval-generator.h"
Alexander Afanasyevfc720362013-01-24 21:49:48 -080029#include "logging.h"
30
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -080031INIT_LOGGER ("FetchManager");
Alexander Afanasyev49a18522013-01-18 17:49:04 -080032
33using namespace boost;
34using namespace std;
35using namespace Ccnx;
36
Alexander Afanasyev83531a42013-01-19 16:21:54 -080037//The disposer object function
38struct fetcher_disposer { void operator() (Fetcher *delete_this) { delete delete_this; } };
39
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080040static const string SCHEDULE_FETCHES_TAG = "ScheduleFetches";
41
Alexander Afanasyev473346f2013-02-07 14:14:45 -080042FetchManager::FetchManager (Ccnx::CcnxWrapperPtr ccnx,
43 const Mapping &mapping,
44 const Name &broadcastForwardingHint,
45 uint32_t parallelFetches, // = 3
46 const SegmentCallback &defaultSegmentCallback,
47 const FinishCallback &defaultFinishCallback,
48 const FetchTaskDbPtr &taskDb
49 )
Alexander Afanasyev49a18522013-01-18 17:49:04 -080050 : m_ccnx (ccnx)
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080051 , m_mapping (mapping)
Alexander Afanasyev83531a42013-01-19 16:21:54 -080052 , m_maxParallelFetches (parallelFetches)
53 , m_currentParallelFetches (0)
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080054 , m_scheduler (new Scheduler)
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080055 , m_executor (new Executor(1))
Zhenkai Zhua0147382013-01-29 15:57:27 -080056 , m_defaultSegmentCallback(defaultSegmentCallback)
57 , m_defaultFinishCallback(defaultFinishCallback)
Zhenkai Zhuda686882013-01-29 22:32:24 -080058 , m_taskDb(taskDb)
Alexander Afanasyev473346f2013-02-07 14:14:45 -080059 , m_broadcastHint (broadcastForwardingHint)
Alexander Afanasyev8811b352013-01-02 12:51:15 -080060{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080061 m_scheduler->start ();
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080062 m_executor->start();
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080063
Alexander Afanasyev4aecad82013-01-31 15:27:08 -080064 m_scheduleFetchesTask = Scheduler::schedulePeriodicTask (m_scheduler,
65 make_shared<SimpleIntervalGenerator> (300), // no need to check to often. if needed, will be rescheduled
66 bind (&FetchManager::ScheduleFetches, this), SCHEDULE_FETCHES_TAG);
Zhenkai Zhuda686882013-01-29 22:32:24 -080067 // resume un-finished fetches if there is any
68 if (m_taskDb)
69 {
70 m_taskDb->foreachTask(bind(&FetchManager::Enqueue, this, _1, _2, _3, _4, _5));
71 }
Alexander Afanasyev49a18522013-01-18 17:49:04 -080072}
Alexander Afanasyeva199f972013-01-02 19:37:26 -080073
Alexander Afanasyev49a18522013-01-18 17:49:04 -080074FetchManager::~FetchManager ()
75{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080076 m_scheduler->shutdown ();
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080077 m_executor->shutdown();
78
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080079 m_ccnx.reset ();
80
Alexander Afanasyev83531a42013-01-19 16:21:54 -080081 m_fetchList.clear_and_dispose (fetcher_disposer ());
Alexander Afanasyev49a18522013-01-18 17:49:04 -080082}
Alexander Afanasyev8811b352013-01-02 12:51:15 -080083
Zhenkai Zhua0147382013-01-29 15:57:27 -080084// Enqueue using default callbacks
85void
86FetchManager::Enqueue (const Ccnx::Name &deviceName, const Ccnx::Name &baseName,
87 uint64_t minSeqNo, uint64_t maxSeqNo, int priority)
88{
89 Enqueue(deviceName, baseName, m_defaultSegmentCallback, m_defaultFinishCallback, minSeqNo, maxSeqNo, priority);
90}
91
Alexander Afanasyev49a18522013-01-18 17:49:04 -080092void
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080093FetchManager::Enqueue (const Ccnx::Name &deviceName, const Ccnx::Name &baseName,
94 const SegmentCallback &segmentCallback, const FinishCallback &finishCallback,
95 uint64_t minSeqNo, uint64_t maxSeqNo, int priority/*PRIORITY_NORMAL*/)
Alexander Afanasyev49a18522013-01-18 17:49:04 -080096{
Zhenkai Zhu454bae22013-01-24 19:27:54 -080097 // Assumption for the following code is minSeqNo <= maxSeqNo
98 if (minSeqNo > maxSeqNo)
99 {
100 return;
101 }
102
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800103 // we may need to guarantee that LookupLocator will gives an answer and not throw exception...
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800104 Name forwardingHint;
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -0800105 forwardingHint = m_mapping (deviceName);
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800106
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800107 if (m_taskDb)
108 {
109 m_taskDb->addTask(deviceName, baseName, minSeqNo, maxSeqNo, priority);
110 }
Zhenkai Zhuda686882013-01-29 22:32:24 -0800111
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800112 unique_lock<mutex> lock (m_parellelFetchMutex);
113
114 _LOG_TRACE ("++++ Create fetcher: " << baseName);
115 Fetcher *fetcher = new Fetcher (m_ccnx,
116 m_executor,
117 segmentCallback,
118 finishCallback,
Zhenkai Zhuda686882013-01-29 22:32:24 -0800119 bind (&FetchManager::DidFetchComplete, this, _1, _2, _3),
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800120 bind (&FetchManager::DidNoDataTimeout, this, _1),
121 deviceName, baseName, minSeqNo, maxSeqNo,
122 boost::posix_time::seconds (30),
123 forwardingHint);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800124
125 switch (priority)
126 {
127 case PRIORITY_HIGH:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800128 _LOG_TRACE ("++++ Push front fetcher: " << fetcher->GetName ());
129 m_fetchList.push_front (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800130 break;
131
132 case PRIORITY_NORMAL:
133 default:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800134 _LOG_TRACE ("++++ Push back fetcher: " << fetcher->GetName ());
135 m_fetchList.push_back (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800136 break;
137 }
138
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800139 _LOG_DEBUG ("++++ Reschedule fetcher task");
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800140 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
141 // ScheduleFetches (); // will start a fetch if m_currentParallelFetches is less than max, otherwise does nothing
Alexander Afanasyev49a18522013-01-18 17:49:04 -0800142}
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800143
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800144void
145FetchManager::ScheduleFetches ()
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800146{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800147 unique_lock<mutex> lock (m_parellelFetchMutex);
148
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800149 boost::posix_time::ptime currentTime = date_time::second_clock<boost::posix_time::ptime>::universal_time ();
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800150 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 -0800151
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800152 for (FetchList::iterator item = m_fetchList.begin ();
153 m_currentParallelFetches < m_maxParallelFetches && item != m_fetchList.end ();
154 item++)
155 {
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800156 if (item->IsActive ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800157 {
158 _LOG_DEBUG ("Item is active");
159 continue;
160 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800161
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800162 if (item->IsTimedWait ())
163 {
164 _LOG_DEBUG ("Item is in timed-wait");
165 continue;
166 }
167
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800168 if (currentTime < item->GetNextScheduledRetry ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800169 {
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800170 if (item->GetNextScheduledRetry () < nextSheduleCheck)
171 nextSheduleCheck = item->GetNextScheduledRetry ();
172
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800173 _LOG_DEBUG ("Item is delayed");
174 continue;
175 }
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800176
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800177 _LOG_DEBUG ("Start fetching of " << item->GetName ());
178
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800179 m_currentParallelFetches ++;
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800180 _LOG_TRACE ("++++ RESTART PIPELINE: " << item->GetName ());
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800181 item->RestartPipeline ();
182 }
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800183
Alexander Afanasyeve10e5f22013-02-08 22:10:13 -0800184 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, (nextSheduleCheck - currentTime).total_seconds ());
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800185}
186
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800187void
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800188FetchManager::DidNoDataTimeout (Fetcher &fetcher)
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800189{
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800190 _LOG_DEBUG ("No data timeout for " << fetcher.GetName () << " with forwarding hint: " << fetcher.GetForwardingHint ());
191
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800192 {
193 unique_lock<mutex> lock (m_parellelFetchMutex);
194 m_currentParallelFetches --;
195 // no need to do anything with the m_fetchList
196 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800197
Alexander Afanasyev473346f2013-02-07 14:14:45 -0800198 if (fetcher.GetForwardingHint () == m_broadcastHint)
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800199 {
200 // try again directly (hopefully with different forwarding hint
201
202 /// @todo Handle potential exception
203 Name forwardingHint;
204 forwardingHint = m_mapping (fetcher.GetDeviceName ());
205 fetcher.SetForwardingHint (forwardingHint);
206 }
207 else
208 {
Alexander Afanasyev473346f2013-02-07 14:14:45 -0800209 fetcher.SetForwardingHint (m_broadcastHint);
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800210 }
211
212 double delay = fetcher.GetRetryPause ();
213 if (delay < 1) // first time
214 {
215 delay = 1;
216 }
217 else
218 {
219 delay = std::min (2*delay, 300.0); // 5 minutes max
220 }
221
222 fetcher.SetRetryPause (delay);
223 fetcher.SetNextScheduledRetry (date_time::second_clock<boost::posix_time::ptime>::universal_time () + posix_time::seconds (delay));
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800224
225 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800226}
227
228void
Zhenkai Zhuda686882013-01-29 22:32:24 -0800229FetchManager::DidFetchComplete (Fetcher &fetcher, const Name &deviceName, const Name &baseName)
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800230{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800231 {
232 unique_lock<mutex> lock (m_parellelFetchMutex);
233 m_currentParallelFetches --;
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800234
235 if (m_taskDb)
236 {
237 m_taskDb->deleteTask(deviceName, baseName);
238 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800239 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800240
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800241 // like TCP timed-wait
242 m_scheduler->scheduleOneTimeTask(m_scheduler, 10, boost::bind(&FetchManager::TimedWait, this, ref(fetcher)), boost::lexical_cast<string>(baseName));
243
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800244 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800245}
Zhenkai Zhu354d46d2013-02-06 13:49:48 -0800246
247void
248FetchManager::TimedWait (Fetcher &fetcher)
249{
250 unique_lock<mutex> lock (m_parellelFetchMutex);
251 _LOG_TRACE ("+++++ removing fetcher: " << fetcher.GetName ());
252 m_fetchList.erase_and_dispose (FetchList::s_iterator_to (fetcher), fetcher_disposer ());
253}