blob: 04cbf03d1082c8a5972fda756fbe684d90856367 [file] [log] [blame]
Weiwei Liue4765012016-06-01 00:10:29 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +00002/*
Davide Pesaventobf1c0692017-01-15 19:15:09 -05003 * Copyright (c) 2016-2017, Regents of the University of California,
4 * Colorado State University,
5 * University Pierre & Marie Curie, Sorbonne University.
Weiwei Liue4765012016-06-01 00:10:29 -07006 *
7 * This file is part of ndn-tools (Named Data Networking Essential Tools).
8 * See AUTHORS.md for complete list of ndn-tools authors and contributors.
9 *
10 * ndn-tools is free software: you can redistribute it and/or modify it under the terms
11 * of the GNU General Public License as published by the Free Software Foundation,
12 * either version 3 of the License, or (at your option) any later version.
13 *
14 * ndn-tools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
15 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along with
19 * ndn-tools, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
20 *
21 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
22 *
23 * @author Wentao Shang
24 * @author Steve DiBenedetto
25 * @author Andrea Tosatto
26 * @author Davide Pesavento
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +000027 * @author Chavoosh Ghasemi
Weiwei Liue4765012016-06-01 00:10:29 -070028 */
29
30#include "pipeline-interests-fixed-window.hpp"
31#include "data-fetcher.hpp"
32
33namespace ndn {
34namespace chunks {
35
36PipelineInterestsFixedWindow::PipelineInterestsFixedWindow(Face& face, const Options& options)
37 : PipelineInterests(face)
38 , m_options(options)
39 , m_nextSegmentNo(0)
40 , m_hasFailure(false)
41{
42 m_segmentFetchers.resize(m_options.maxPipelineSize);
43}
44
45PipelineInterestsFixedWindow::~PipelineInterestsFixedWindow()
46{
47 cancel();
48}
49
50void
51PipelineInterestsFixedWindow::doRun()
52{
53 // if the FinalBlockId is unknown, this could potentially request non-existent segments
54 for (size_t nRequestedSegments = 0;
55 nRequestedSegments < m_options.maxPipelineSize;
56 ++nRequestedSegments) {
57 if (!fetchNextSegment(nRequestedSegments))
58 // all segments have been requested
59 break;
60 }
61}
62
63bool
64PipelineInterestsFixedWindow::fetchNextSegment(std::size_t pipeNo)
65{
66 if (isStopping())
67 return false;
68
69 if (m_hasFailure) {
70 onFailure("Fetching terminated but no final segment number has been found");
71 return false;
72 }
73
74 if (m_nextSegmentNo == m_excludedSegmentNo)
75 m_nextSegmentNo++;
76
77 if (m_hasFinalBlockId && m_nextSegmentNo > m_lastSegmentNo)
78 return false;
79
80 // send interest for next segment
81 if (m_options.isVerbose)
82 std::cerr << "Requesting segment #" << m_nextSegmentNo << std::endl;
83
84 Interest interest(Name(m_prefix).appendSegment(m_nextSegmentNo));
85 interest.setInterestLifetime(m_options.interestLifetime);
86 interest.setMustBeFresh(m_options.mustBeFresh);
87 interest.setMaxSuffixComponents(1);
88
89 auto fetcher = DataFetcher::fetch(m_face, interest,
90 m_options.maxRetriesOnTimeoutOrNack,
91 m_options.maxRetriesOnTimeoutOrNack,
92 bind(&PipelineInterestsFixedWindow::handleData, this, _1, _2, pipeNo),
93 bind(&PipelineInterestsFixedWindow::handleFail, this, _2, pipeNo),
94 bind(&PipelineInterestsFixedWindow::handleFail, this, _2, pipeNo),
95 m_options.isVerbose);
96
97 BOOST_ASSERT(!m_segmentFetchers[pipeNo].first || !m_segmentFetchers[pipeNo].first->isRunning());
98 m_segmentFetchers[pipeNo] = make_pair(fetcher, m_nextSegmentNo);
99 m_nextSegmentNo++;
100
101 return true;
102}
103
104void
105PipelineInterestsFixedWindow::doCancel()
106{
107 for (auto& fetcher : m_segmentFetchers) {
108 if (fetcher.first)
109 fetcher.first->cancel();
110 }
111
112 m_segmentFetchers.clear();
113}
114
115void
116PipelineInterestsFixedWindow::handleData(const Interest& interest, const Data& data, size_t pipeNo)
117{
118 if (isStopping())
119 return;
120
121 BOOST_ASSERT(data.getName().equals(interest.getName()));
122
123 if (m_options.isVerbose)
Davide Pesaventobf1c0692017-01-15 19:15:09 -0500124 std::cerr << "Received segment #" << getSegmentFromPacket(data) << std::endl;
Weiwei Liue4765012016-06-01 00:10:29 -0700125
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +0000126 m_nReceived++;
127 m_receivedSize += data.getContent().value_size();
128
Weiwei Liue4765012016-06-01 00:10:29 -0700129 onData(interest, data);
130
131 if (!m_hasFinalBlockId && !data.getFinalBlockId().empty()) {
132 m_lastSegmentNo = data.getFinalBlockId().toSegment();
133 m_hasFinalBlockId = true;
134
135 for (auto& fetcher : m_segmentFetchers) {
136 if (fetcher.first == nullptr)
137 continue;
138
139 if (fetcher.second > m_lastSegmentNo) {
140 // stop trying to fetch segments that are beyond m_lastSegmentNo
141 fetcher.first->cancel();
142 }
143 else if (fetcher.first->hasError()) { // fetcher.second <= m_lastSegmentNo
144 // there was an error while fetching a segment that is part of the content
145 return onFailure("Failure retrieving segment #" + to_string(fetcher.second));
146 }
147 }
148 }
149
Chavoosh Ghasemi4d36ed52017-10-31 22:26:25 +0000150 BOOST_ASSERT(m_nReceived > 0);
151 if (m_hasFinalBlockId &&
152 static_cast<uint64_t>(m_nReceived - 1) >= m_lastSegmentNo) { // all segments have been received
153 if (m_options.isVerbose) {
154 printSummary();
155 }
156 }
157 else {
158 fetchNextSegment(pipeNo);
159 }
Weiwei Liue4765012016-06-01 00:10:29 -0700160}
161
162void PipelineInterestsFixedWindow::handleFail(const std::string& reason, std::size_t pipeNo)
163{
164 if (isStopping())
165 return;
166
167 // if the failed segment is definitely part of the content, raise a fatal error
168 if (m_hasFinalBlockId && m_segmentFetchers[pipeNo].second <= m_lastSegmentNo)
169 return onFailure(reason);
170
171 if (!m_hasFinalBlockId) {
172 bool areAllFetchersStopped = true;
173 for (auto& fetcher : m_segmentFetchers) {
174 if (fetcher.first == nullptr)
175 continue;
176
177 // cancel fetching all segments that follow
178 if (fetcher.second > m_segmentFetchers[pipeNo].second) {
179 fetcher.first->cancel();
180 }
181 else if (fetcher.first->isRunning()) { // fetcher.second <= m_segmentFetchers[pipeNo].second
182 areAllFetchersStopped = false;
183 }
184 }
185
186 if (areAllFetchersStopped) {
187 onFailure("Fetching terminated but no final segment number has been found");
188 }
189 else {
190 m_hasFailure = true;
191 }
192 }
193}
194
195} // namespace chunks
196} // namespace ndn