blob: 8d98207afb13f3abbef0a62264c019aca69a7284 [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>
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080026
27#include "simple-interval-generator.h"
Alexander Afanasyevfc720362013-01-24 21:49:48 -080028#include "logging.h"
29
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -080030INIT_LOGGER ("FetchManager");
Alexander Afanasyev49a18522013-01-18 17:49:04 -080031
32using namespace boost;
33using namespace std;
34using namespace Ccnx;
35
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080036static const Name BROADCAST_DOMAIN = Name ("/ndn/broadcast/chronoshare");
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
Zhenkai Zhua0147382013-01-29 15:57:27 -080042FetchManager::FetchManager (Ccnx::CcnxWrapperPtr ccnx
43 , const Mapping &mapping
44 , uint32_t parallelFetches // = 3
45 , const SegmentCallback &defaultSegmentCallback
46 , const FinishCallback &defaultFinishCallback
47 )
Alexander Afanasyev49a18522013-01-18 17:49:04 -080048 : m_ccnx (ccnx)
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080049 , m_mapping (mapping)
Alexander Afanasyev83531a42013-01-19 16:21:54 -080050 , m_maxParallelFetches (parallelFetches)
51 , m_currentParallelFetches (0)
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080052 , m_scheduler (new Scheduler)
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080053 , m_executor (new Executor(1))
Zhenkai Zhua0147382013-01-29 15:57:27 -080054 , m_defaultSegmentCallback(defaultSegmentCallback)
55 , m_defaultFinishCallback(defaultFinishCallback)
Alexander Afanasyev8811b352013-01-02 12:51:15 -080056{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080057 m_scheduler->start ();
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080058 m_executor->start();
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080059
60 m_scheduleFetchesTask = Scheduler::schedulePeriodicTask (m_scheduler,
Alexander Afanasyevf9756232013-01-28 16:42:20 -080061 make_shared<SimpleIntervalGenerator> (300), // no need to check to often. if needed, will be rescheduled
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080062 bind (&FetchManager::ScheduleFetches, this), SCHEDULE_FETCHES_TAG);
Alexander Afanasyev49a18522013-01-18 17:49:04 -080063}
Alexander Afanasyeva199f972013-01-02 19:37:26 -080064
Alexander Afanasyev49a18522013-01-18 17:49:04 -080065FetchManager::~FetchManager ()
66{
Alexander Afanasyev548d38d2013-01-26 16:36:06 -080067 m_scheduler->shutdown ();
68
Zhenkai Zhuab9215c2013-01-28 23:42:28 -080069 m_executor->shutdown();
70
Alexander Afanasyev83531a42013-01-19 16:21:54 -080071 m_fetchList.clear_and_dispose (fetcher_disposer ());
Alexander Afanasyev49a18522013-01-18 17:49:04 -080072}
Alexander Afanasyev8811b352013-01-02 12:51:15 -080073
Zhenkai Zhua0147382013-01-29 15:57:27 -080074// Enqueue using default callbacks
75void
76FetchManager::Enqueue (const Ccnx::Name &deviceName, const Ccnx::Name &baseName,
77 uint64_t minSeqNo, uint64_t maxSeqNo, int priority)
78{
79 Enqueue(deviceName, baseName, m_defaultSegmentCallback, m_defaultFinishCallback, minSeqNo, maxSeqNo, priority);
80}
81
Alexander Afanasyev49a18522013-01-18 17:49:04 -080082void
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080083FetchManager::Enqueue (const Ccnx::Name &deviceName, const Ccnx::Name &baseName,
84 const SegmentCallback &segmentCallback, const FinishCallback &finishCallback,
85 uint64_t minSeqNo, uint64_t maxSeqNo, int priority/*PRIORITY_NORMAL*/)
Alexander Afanasyev49a18522013-01-18 17:49:04 -080086{
Zhenkai Zhu454bae22013-01-24 19:27:54 -080087 // Assumption for the following code is minSeqNo <= maxSeqNo
88 if (minSeqNo > maxSeqNo)
89 {
90 return;
91 }
92
Alexander Afanasyev83531a42013-01-19 16:21:54 -080093 // we may need to guarantee that LookupLocator will gives an answer and not throw exception...
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080094 Name forwardingHint;
Zhenkai Zhu3d1beca2013-01-23 14:55:32 -080095 forwardingHint = m_mapping (deviceName);
Alexander Afanasyev21a166e2013-01-20 16:04:41 -080096
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -080097 unique_lock<mutex> lock (m_parellelFetchMutex);
98
99 _LOG_TRACE ("++++ Create fetcher: " << baseName);
100 Fetcher *fetcher = new Fetcher (m_ccnx,
101 m_executor,
102 segmentCallback,
103 finishCallback,
104 bind (&FetchManager::DidFetchComplete, this, _1),
105 bind (&FetchManager::DidNoDataTimeout, this, _1),
106 deviceName, baseName, minSeqNo, maxSeqNo,
107 boost::posix_time::seconds (30),
108 forwardingHint);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800109
110 switch (priority)
111 {
112 case PRIORITY_HIGH:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800113 _LOG_TRACE ("++++ Push front fetcher: " << fetcher->GetName ());
114 m_fetchList.push_front (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800115 break;
116
117 case PRIORITY_NORMAL:
118 default:
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800119 _LOG_TRACE ("++++ Push back fetcher: " << fetcher->GetName ());
120 m_fetchList.push_back (*fetcher);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800121 break;
122 }
123
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800124 _LOG_DEBUG ("++++ Reschedule fetcher task");
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800125 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
126 // ScheduleFetches (); // will start a fetch if m_currentParallelFetches is less than max, otherwise does nothing
Alexander Afanasyev49a18522013-01-18 17:49:04 -0800127}
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800128
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800129void
130FetchManager::ScheduleFetches ()
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800131{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800132 unique_lock<mutex> lock (m_parellelFetchMutex);
133
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800134 boost::posix_time::ptime currentTime = date_time::second_clock<boost::posix_time::ptime>::universal_time ();
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800135 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 -0800136
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800137 for (FetchList::iterator item = m_fetchList.begin ();
138 m_currentParallelFetches < m_maxParallelFetches && item != m_fetchList.end ();
139 item++)
140 {
Alexander Afanasyev21a166e2013-01-20 16:04:41 -0800141 if (item->IsActive ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800142 {
143 _LOG_DEBUG ("Item is active");
144 continue;
145 }
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800146
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800147 if (currentTime < item->GetNextScheduledRetry ())
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800148 {
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800149 if (item->GetNextScheduledRetry () < nextSheduleCheck)
150 nextSheduleCheck = item->GetNextScheduledRetry ();
151
Alexander Afanasyevf8b22bf2013-01-26 17:28:11 -0800152 _LOG_DEBUG ("Item is delayed");
153 continue;
154 }
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800155
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800156 _LOG_DEBUG ("Start fetching of " << item->GetName ());
157
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800158 m_currentParallelFetches ++;
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800159 _LOG_TRACE ("++++ RESTART PIPELINE: " << item->GetName ());
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800160 item->RestartPipeline ();
161 }
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800162
163 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, (nextSheduleCheck - currentTime).seconds ());
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800164}
165
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800166void
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800167FetchManager::DidNoDataTimeout (Fetcher &fetcher)
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800168{
Alexander Afanasyevff8d9dc2013-01-26 00:45:08 -0800169 _LOG_DEBUG ("No data timeout for " << fetcher.GetName () << " with forwarding hint: " << fetcher.GetForwardingHint ());
170
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800171 {
172 unique_lock<mutex> lock (m_parellelFetchMutex);
173 m_currentParallelFetches --;
174 // no need to do anything with the m_fetchList
175 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800176
Alexander Afanasyev548d38d2013-01-26 16:36:06 -0800177 if (fetcher.GetForwardingHint () == BROADCAST_DOMAIN)
178 {
179 // try again directly (hopefully with different forwarding hint
180
181 /// @todo Handle potential exception
182 Name forwardingHint;
183 forwardingHint = m_mapping (fetcher.GetDeviceName ());
184 fetcher.SetForwardingHint (forwardingHint);
185 }
186 else
187 {
188 fetcher.SetForwardingHint (BROADCAST_DOMAIN);
189 }
190
191 double delay = fetcher.GetRetryPause ();
192 if (delay < 1) // first time
193 {
194 delay = 1;
195 }
196 else
197 {
198 delay = std::min (2*delay, 300.0); // 5 minutes max
199 }
200
201 fetcher.SetRetryPause (delay);
202 fetcher.SetNextScheduledRetry (date_time::second_clock<boost::posix_time::ptime>::universal_time () + posix_time::seconds (delay));
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800203
204 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800205}
206
207void
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800208FetchManager::DidFetchComplete (Fetcher &fetcher)
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800209{
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800210 {
211 unique_lock<mutex> lock (m_parellelFetchMutex);
212 m_currentParallelFetches --;
Alexander Afanasyevbc8bf232013-01-29 11:19:17 -0800213 _LOG_TRACE ("+++++ removing fetcher: " << fetcher.GetName ());
Alexander Afanasyev83531a42013-01-19 16:21:54 -0800214 m_fetchList.erase_and_dispose (FetchList::s_iterator_to (fetcher), fetcher_disposer ());
215 }
Alexander Afanasyevd6c2a902013-01-19 21:24:30 -0800216
Alexander Afanasyevf9756232013-01-28 16:42:20 -0800217 m_scheduler->rescheduleTaskAt (m_scheduleFetchesTask, 0);
Alexander Afanasyeve41e7d22013-01-19 15:13:47 -0800218}