blob: 08e951b961ceb16fd5b8fe1e5b9070b761cf8b31 [file] [log] [blame]
Shuo Chen29c77fe2014-03-18 11:29:41 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/**
Alexander Afanasyeve1e6f2a2014-04-25 11:28:12 -07003 * Copyright (c) 2014, Regents of the University of California.
4 *
5 * This file is part of NDN repo-ng (Next generation of NDN repository).
6 * See AUTHORS.md for complete list of repo-ng authors and contributors.
7 *
8 * repo-ng is free software: you can redistribute it and/or modify it under the terms
9 * of the GNU General Public License as published by the Free Software Foundation,
10 * either version 3 of the License, or (at your option) any later version.
11 *
12 * repo-ng is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
13 * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 * PURPOSE. See the GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along with
17 * repo-ng, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
Shuo Chen29c77fe2014-03-18 11:29:41 -070018 */
19
20#include "write-handle.hpp"
21
22namespace repo {
23
24static const int RETRY_TIMEOUT = 3;
25static const int DEFAULT_CREDIT = 12;
Weiqi Shi098f91c2014-07-23 17:41:35 -070026static const milliseconds NOEND_TIMEOUT(10000);
27static const milliseconds PROCESS_DELETE_TIME(10000);
28static const milliseconds DEFAULT_INTEREST_LIFETIME(4000);
Shuo Chen29c77fe2014-03-18 11:29:41 -070029
Weiqi Shif0330d52014-07-09 10:54:27 -070030WriteHandle::WriteHandle(Face& face, RepoStorage& storageHandle, KeyChain& keyChain,
31 Scheduler& scheduler,// RepoStorage& storeindex,
32 ValidatorConfig& validator)
Shuo Chen29c77fe2014-03-18 11:29:41 -070033 : BaseHandle(face, storageHandle, keyChain, scheduler)
34 , m_validator(validator)
35 , m_retryTime(RETRY_TIMEOUT)
36 , m_credit(DEFAULT_CREDIT)
37 , m_noEndTimeout(NOEND_TIMEOUT)
Weiqi Shi098f91c2014-07-23 17:41:35 -070038 , m_interestLifetime(DEFAULT_INTEREST_LIFETIME)
Shuo Chen29c77fe2014-03-18 11:29:41 -070039{
40}
41
42void
43WriteHandle::deleteProcess(ProcessId processId)
44{
45 m_processes.erase(processId);
46}
47
48// Interest.
49void
50WriteHandle::onInterest(const Name& prefix, const Interest& interest)
51{
52 m_validator.validate(interest,
Shuo Chenc88c87d2014-06-25 20:21:02 +080053 bind(&WriteHandle::onValidated, this, _1, prefix),
54 bind(&WriteHandle::onValidationFailed, this, _1, _2));
Shuo Chen29c77fe2014-03-18 11:29:41 -070055}
56
57// onRegisterFailed.
58void
59WriteHandle::onRegisterFailed(const Name& prefix, const std::string& reason)
60{
Shuo Chenc88c87d2014-06-25 20:21:02 +080061 std::cerr << reason << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -070062 throw Error("Insert prefix registration failed");
63}
64
65// onRegisterFailed for insert.
66void
67WriteHandle::onCheckRegisterFailed(const Name& prefix, const std::string& reason)
68{
Shuo Chenc88c87d2014-06-25 20:21:02 +080069 std::cerr << reason << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -070070 throw Error("Insert check prefix registration failed");
71}
72
73void
Wentao Shanga8f3c402014-10-30 14:03:27 -070074WriteHandle::onValidated(const std::shared_ptr<const Interest>& interest, const Name& prefix)
Shuo Chen29c77fe2014-03-18 11:29:41 -070075{
76 //m_validResult = 1;
77 RepoCommandParameter parameter;
78 try {
79 extractParameter(*interest, prefix, parameter);
80 }
81 catch (RepoCommandParameter::Error) {
82 negativeReply(*interest, 403);
83 return;
84 }
85
86 if (parameter.hasStartBlockId() || parameter.hasEndBlockId()) {
87 if (parameter.hasSelectors()) {
88 negativeReply(*interest, 402);
89 return;
90 }
91 processSegmentedInsertCommand(*interest, parameter);
92 }
93 else {
94 processSingleInsertCommand(*interest, parameter);
95 }
Weiqi Shi098f91c2014-07-23 17:41:35 -070096 if (parameter.hasInterestLifetime())
97 m_interestLifetime = parameter.getInterestLifetime();
Shuo Chen29c77fe2014-03-18 11:29:41 -070098}
99
100void
Wentao Shanga8f3c402014-10-30 14:03:27 -0700101WriteHandle::onValidationFailed(const std::shared_ptr<const Interest>& interest,
102 const std::string& reason)
Shuo Chen29c77fe2014-03-18 11:29:41 -0700103{
Shuo Chen028dcd32014-06-21 16:36:44 +0800104 std::cerr << reason << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700105 negativeReply(*interest, 401);
106}
107
108void
Wentao Shanga8f3c402014-10-30 14:03:27 -0700109WriteHandle::onData(const Interest& interest, Data& data, ProcessId processId)
Shuo Chen29c77fe2014-03-18 11:29:41 -0700110{
Shuo Chenc88c87d2014-06-25 20:21:02 +0800111 m_validator.validate(data,
112 bind(&WriteHandle::onDataValidated, this, interest, _1, processId),
113 bind(&WriteHandle::onDataValidationFailed, this, _1, _2));
114}
115
116void
Wentao Shanga8f3c402014-10-30 14:03:27 -0700117WriteHandle::onDataValidated(const Interest& interest,
118 const std::shared_ptr<const Data>& data,
Shuo Chenc88c87d2014-06-25 20:21:02 +0800119 ProcessId processId)
120{
Shuo Chen29c77fe2014-03-18 11:29:41 -0700121 if (m_processes.count(processId) == 0) {
122 return;
123 }
124
125 ProcessInfo& process = m_processes[processId];
126 RepoCommandResponse& response = process.response;
127
128 if (response.getInsertNum() == 0) {
Shuo Chenc88c87d2014-06-25 20:21:02 +0800129 getStorageHandle().insertData(*data);
Weiqi Shif0330d52014-07-09 10:54:27 -0700130 // getStorageHandle().insertEntry(*data);
131 // getStoreIndex().insert(*data);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700132 response.setInsertNum(1);
133 }
134
135 deferredDeleteProcess(processId);
136}
137
138void
Wentao Shanga8f3c402014-10-30 14:03:27 -0700139WriteHandle::onDataValidationFailed(const std::shared_ptr<const Data>& data,
140 const std::string& reason)
Shuo Chenc88c87d2014-06-25 20:21:02 +0800141{
142 std::cerr << reason << std::endl;
143}
144
145void
Shuo Chen29c77fe2014-03-18 11:29:41 -0700146WriteHandle::onSegmentData(const Interest& interest, Data& data, ProcessId processId)
147{
Shuo Chenc88c87d2014-06-25 20:21:02 +0800148 m_validator.validate(data,
149 bind(&WriteHandle::onSegmentDataValidated, this, interest, _1, processId),
150 bind(&WriteHandle::onDataValidationFailed, this, _1, _2));
151}
152
153void
154WriteHandle::onSegmentDataValidated(const Interest& interest,
Wentao Shanga8f3c402014-10-30 14:03:27 -0700155 const std::shared_ptr<const Data>& data,
Shuo Chenc88c87d2014-06-25 20:21:02 +0800156 ProcessId processId)
157{
Shuo Chen29c77fe2014-03-18 11:29:41 -0700158 if (m_processes.count(processId) == 0) {
159 return;
160 }
161 RepoCommandResponse& response = m_processes[processId].response;
162
163 //refresh endBlockId
Shuo Chenc88c87d2014-06-25 20:21:02 +0800164 Name::Component finalBlockId = data->getFinalBlockId();
Shuo Chen29c77fe2014-03-18 11:29:41 -0700165
166 if (!finalBlockId.empty()) {
167 SegmentNo final = finalBlockId.toSegment();
168 if (response.hasEndBlockId()) {
169 if (final < response.getEndBlockId()) {
170 response.setEndBlockId(final);
171 }
172 }
173 else {
174 response.setEndBlockId(final);
175 }
176 }
177
178 //insert data
Shuo Chenc88c87d2014-06-25 20:21:02 +0800179 if (getStorageHandle().insertData(*data)) {
Shuo Chen29c77fe2014-03-18 11:29:41 -0700180 response.setInsertNum(response.getInsertNum() + 1);
181 }
Shuo Chen29c77fe2014-03-18 11:29:41 -0700182
183 onSegmentDataControl(processId, interest);
184}
185
186void
Wentao Shanga8f3c402014-10-30 14:03:27 -0700187WriteHandle::onTimeout(const Interest& interest, ProcessId processId)
Shuo Chen29c77fe2014-03-18 11:29:41 -0700188{
Shuo Chen028dcd32014-06-21 16:36:44 +0800189 std::cerr << "Timeout" << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700190 m_processes.erase(processId);
191}
192
193void
194WriteHandle::onSegmentTimeout(const Interest& interest, ProcessId processId)
195{
Shuo Chen028dcd32014-06-21 16:36:44 +0800196 std::cerr << "SegTimeout" << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700197
198 onSegmentTimeoutControl(processId, interest);
199}
200
201void
202WriteHandle::listen(const Name& prefix)
203{
204 Name insertPrefix;
205 insertPrefix.append(prefix).append("insert");
Weiqi Shif0330d52014-07-09 10:54:27 -0700206 ndn::InterestFilter filter_insert(insertPrefix);
207 getFace().setInterestFilter(filter_insert,
Shuo Chen29c77fe2014-03-18 11:29:41 -0700208 bind(&WriteHandle::onInterest, this, _1, _2),
209 bind(&WriteHandle::onRegisterFailed, this, _1, _2));
210 Name insertCheckPrefix;
211 insertCheckPrefix.append(prefix).append("insert check");
Weiqi Shif0330d52014-07-09 10:54:27 -0700212 ndn::InterestFilter filter_insertCheck(insertCheckPrefix);
213 getFace().setInterestFilter(filter_insertCheck,
Shuo Chen29c77fe2014-03-18 11:29:41 -0700214 bind(&WriteHandle::onCheckInterest, this, _1, _2),
215 bind(&WriteHandle::onRegisterFailed, this, _1, _2));
216}
217
218void
219WriteHandle::segInit(ProcessId processId, const RepoCommandParameter& parameter)
220{
221 ProcessInfo& process = m_processes[processId];
222 process.credit = 0;
223
224 map<SegmentNo, int>& processRetry = process.retryCounts;
225
226 Name name = parameter.getName();
227 SegmentNo startBlockId = parameter.getStartBlockId();
228
229 uint64_t initialCredit = m_credit;
230
231 if (parameter.hasEndBlockId()) {
232 initialCredit =
Shuo Chen39fe8da2014-04-30 00:00:35 +0800233 std::min(initialCredit, parameter.getEndBlockId() - parameter.getStartBlockId() + 1);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700234 }
235 else {
236 // set noEndTimeout timer
237 process.noEndTime = ndn::time::steady_clock::now() +
238 m_noEndTimeout;
239 }
240 process.credit = initialCredit;
241 SegmentNo segment = startBlockId;
Weiqi Shi098f91c2014-07-23 17:41:35 -0700242
Shuo Chen29c77fe2014-03-18 11:29:41 -0700243 for (; segment < startBlockId + initialCredit; ++segment) {
244 Name fetchName = name;
245 fetchName.appendSegment(segment);
246 Interest interest(fetchName);
Weiqi Shi098f91c2014-07-23 17:41:35 -0700247 interest.setInterestLifetime(m_interestLifetime);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700248 getFace().expressInterest(interest,
249 bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
250 bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
251 process.credit--;
252 processRetry[segment] = 0;
253 }
254
255 queue<SegmentNo>& nextSegmentQueue = process.nextSegmentQueue;
256
Shuo Chen29c77fe2014-03-18 11:29:41 -0700257 process.nextSegment = segment;
258 nextSegmentQueue.push(segment);
259}
260
261void
262WriteHandle::onSegmentDataControl(ProcessId processId, const Interest& interest)
263{
Shuo Chen29c77fe2014-03-18 11:29:41 -0700264 if (m_processes.count(processId) == 0) {
265 return;
266 }
267 ProcessInfo& process = m_processes[processId];
268 RepoCommandResponse& response = process.response;
269 int& processCredit = process.credit;
270 //onSegmentDataControl is called when a data returns.
271 //When data returns, processCredit++
272 processCredit++;
273 SegmentNo& nextSegment = process.nextSegment;
274 queue<SegmentNo>& nextSegmentQueue = process.nextSegmentQueue;
275 map<SegmentNo, int>& retryCounts = process.retryCounts;
276
277 //read whether notime timeout
278 if (!response.hasEndBlockId()) {
279
280 ndn::time::steady_clock::TimePoint& noEndTime = process.noEndTime;
281 ndn::time::steady_clock::TimePoint now = ndn::time::steady_clock::now();
282
283 if (now > noEndTime) {
Shuo Chen028dcd32014-06-21 16:36:44 +0800284 std::cerr << "noEndtimeout: " << processId << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700285 //m_processes.erase(processId);
286 //StatusCode should be refreshed as 405
287 response.setStatusCode(405);
288 //schedule a delete event
289 deferredDeleteProcess(processId);
290 return;
291 }
292 }
293
294 //read whether this process has total ends, if ends, remove control info from the maps
295 if (response.hasEndBlockId()) {
296 uint64_t nSegments =
297 response.getEndBlockId() - response.getStartBlockId() + 1;
298 if (response.getInsertNum() >= nSegments) {
299 //m_processes.erase(processId);
300 //All the data has been inserted, StatusCode is refreshed as 200
301 response.setStatusCode(200);
302 deferredDeleteProcess(processId);
303 return;
304 }
305 }
306
307 //check whether there is any credit
308 if (processCredit == 0)
309 return;
310
311
312 //check whether sent queue empty
313 if (nextSegmentQueue.empty()) {
314 //do not do anything
315 return;
316 }
317
318 //pop the queue
319 SegmentNo sendingSegment = nextSegmentQueue.front();
320 nextSegmentQueue.pop();
321
322 //check whether sendingSegment exceeds
Shuo Chenccfbe242014-04-29 23:57:51 +0800323 if (response.hasEndBlockId() && sendingSegment > response.getEndBlockId()) {
Shuo Chen29c77fe2014-03-18 11:29:41 -0700324 //do not do anything
325 return;
326 }
327
328 //read whether this is retransmitted data;
329 SegmentNo fetchedSegment =
330 interest.getName().get(interest.getName().size() - 1).toSegment();
331
332 BOOST_ASSERT(retryCounts.count(fetchedSegment) != 0);
333
334 //find this fetched data, remove it from this map
335 //rit->second.erase(oit);
336 retryCounts.erase(fetchedSegment);
337 //express the interest of the top of the queue
338 Name fetchName(interest.getName().getPrefix(-1));
339 fetchName.appendSegment(sendingSegment);
340 Interest fetchInterest(fetchName);
Weiqi Shi098f91c2014-07-23 17:41:35 -0700341 fetchInterest.setInterestLifetime(m_interestLifetime);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700342 getFace().expressInterest(fetchInterest,
343 bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
344 bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
345 //When an interest is expressed, processCredit--
346 processCredit--;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700347 if (retryCounts.count(sendingSegment) == 0) {
348 //not found
349 retryCounts[sendingSegment] = 0;
350 }
351 else {
352 //found
353 retryCounts[sendingSegment] = retryCounts[sendingSegment] + 1;
354 }
355 //increase the next seg and put it into the queue
Shuo Chenccfbe242014-04-29 23:57:51 +0800356 if (!response.hasEndBlockId() || (nextSegment + 1) <= response.getEndBlockId()) {
Shuo Chen29c77fe2014-03-18 11:29:41 -0700357 nextSegment++;
358 nextSegmentQueue.push(nextSegment);
359 }
360}
361
362void
363WriteHandle::onSegmentTimeoutControl(ProcessId processId, const Interest& interest)
364{
365 if (m_processes.count(processId) == 0) {
366 return;
367 }
368 ProcessInfo& process = m_processes[processId];
Shuo Chen09f09bb2014-03-18 15:37:11 -0700369 // RepoCommandResponse& response = process.response;
370 // SegmentNo& nextSegment = process.nextSegment;
371 // queue<SegmentNo>& nextSegmentQueue = process.nextSegmentQueue;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700372 map<SegmentNo, int>& retryCounts = process.retryCounts;
373
374 SegmentNo timeoutSegment = interest.getName().get(-1).toSegment();
375
Shuo Chen028dcd32014-06-21 16:36:44 +0800376 std::cerr << "timeoutSegment: " << timeoutSegment << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700377
378 BOOST_ASSERT(retryCounts.count(timeoutSegment) != 0);
379
380 //read the retry time. If retry out of time, fail the process. if not, plus
381 int& retryTime = retryCounts[timeoutSegment];
382 if (retryTime >= m_retryTime) {
383 //fail this process
Shuo Chen028dcd32014-06-21 16:36:44 +0800384 std::cerr << "Retry timeout: " << processId << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700385 m_processes.erase(processId);
386 return;
387 }
388 else {
389 //Reput it in the queue, retryTime++
390 retryTime++;
391 Interest retryInterest(interest.getName());
Weiqi Shi098f91c2014-07-23 17:41:35 -0700392 retryInterest.setInterestLifetime(m_interestLifetime);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700393 getFace().expressInterest(retryInterest,
394 bind(&WriteHandle::onSegmentData, this, _1, _2, processId),
395 bind(&WriteHandle::onSegmentTimeout, this, _1, processId));
396 }
397
398}
399
400void
401WriteHandle::onCheckInterest(const Name& prefix, const Interest& interest)
402{
403 m_validator.validate(interest,
Shuo Chenc88c87d2014-06-25 20:21:02 +0800404 bind(&WriteHandle::onCheckValidated, this, _1, prefix),
405 bind(&WriteHandle::onCheckValidationFailed, this, _1, _2));
Shuo Chen29c77fe2014-03-18 11:29:41 -0700406
407}
408
409void
410WriteHandle::onCheckValidated(const shared_ptr<const Interest>& interest, const Name& prefix)
411{
412 RepoCommandParameter parameter;
413 try {
414 extractParameter(*interest, prefix, parameter);
415 }
416 catch (RepoCommandParameter::Error) {
417 negativeReply(*interest, 403);
418 return;
419 }
420
421 if (!parameter.hasProcessId()) {
422 negativeReply(*interest, 403);
423 return;
424 }
425 //check whether this process exists
426 ProcessId processId = parameter.getProcessId();
427 if (m_processes.count(processId) == 0) {
Shuo Chen028dcd32014-06-21 16:36:44 +0800428 std::cerr << "no such processId: " << processId << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700429 negativeReply(*interest, 404);
430 return;
431 }
432
433 ProcessInfo& process = m_processes[processId];
434
435 RepoCommandResponse& response = process.response;
436
437 //Check whether it is single data fetching
438 if (!response.hasStartBlockId() &&
439 !response.hasEndBlockId()) {
440 reply(*interest, response);
441 return;
442 }
443
444 //read if noEndtimeout
445 if (!response.hasEndBlockId()) {
446 extendNoEndTime(process);
447 reply(*interest, response);
448 return;
449 }
450 else {
451 reply(*interest, response);
452 }
453}
454
455void
Shuo Chenc88c87d2014-06-25 20:21:02 +0800456WriteHandle::onCheckValidationFailed(const shared_ptr<const Interest>& interest,
457 const std::string& reason)
Shuo Chen29c77fe2014-03-18 11:29:41 -0700458{
Shuo Chenc88c87d2014-06-25 20:21:02 +0800459 std::cerr << reason << std::endl;
Shuo Chen29c77fe2014-03-18 11:29:41 -0700460 negativeReply(*interest, 401);
461}
462
463void
464WriteHandle::deferredDeleteProcess(ProcessId processId)
465{
466 getScheduler().scheduleEvent(PROCESS_DELETE_TIME,
467 ndn::bind(&WriteHandle::deleteProcess, this, processId));
468}
469
470void
471WriteHandle::processSingleInsertCommand(const Interest& interest,
472 RepoCommandParameter& parameter)
473{
474 ProcessId processId = generateProcessId();
475
476 ProcessInfo& process = m_processes[processId];
477
478 RepoCommandResponse& response = process.response;
479 response.setStatusCode(100);
480 response.setProcessId(processId);
481 response.setInsertNum(0);
482
483 reply(interest, response);
484
485 response.setStatusCode(300);
486
487 Interest fetchInterest(parameter.getName());
Weiqi Shi098f91c2014-07-23 17:41:35 -0700488 fetchInterest.setInterestLifetime(m_interestLifetime);
Shuo Chen29c77fe2014-03-18 11:29:41 -0700489 if (parameter.hasSelectors()) {
490 fetchInterest.setSelectors(parameter.getSelectors());
491 }
492 getFace().expressInterest(fetchInterest,
493 bind(&WriteHandle::onData, this, _1, _2, processId),
494 bind(&WriteHandle::onTimeout, this, _1, processId));
495}
496
497void
498WriteHandle::processSegmentedInsertCommand(const Interest& interest,
499 RepoCommandParameter& parameter)
500{
501 if (parameter.hasEndBlockId()) {
502 //normal fetch segment
503 if (!parameter.hasStartBlockId()) {
504 parameter.setStartBlockId(0);
505 }
506
507 SegmentNo startBlockId = parameter.getStartBlockId();
508 SegmentNo endBlockId = parameter.getEndBlockId();
Shuo Chen29c77fe2014-03-18 11:29:41 -0700509 if (startBlockId > endBlockId) {
510 negativeReply(interest, 403);
511 return;
512 }
513
514 ProcessId processId = generateProcessId();
515 ProcessInfo& process = m_processes[processId];
Shuo Chen29c77fe2014-03-18 11:29:41 -0700516 RepoCommandResponse& response = process.response;
517 response.setStatusCode(100);
518 response.setProcessId(processId);
519 response.setInsertNum(0);
520 response.setStartBlockId(startBlockId);
521 response.setEndBlockId(endBlockId);
522
523 reply(interest, response);
524
525 //300 means data fetching is in progress
526 response.setStatusCode(300);
527
528 segInit(processId, parameter);
529 }
530 else {
531 //no EndBlockId, so fetch FinalBlockId in data, if timeout, stop
532 ProcessId processId = generateProcessId();
533 ProcessInfo& process = m_processes[processId];
Shuo Chen29c77fe2014-03-18 11:29:41 -0700534 RepoCommandResponse& response = process.response;
535 response.setStatusCode(100);
536 response.setProcessId(processId);
537 response.setInsertNum(0);
538 response.setStartBlockId(parameter.getStartBlockId());
539 reply(interest, response);
540
541 //300 means data fetching is in progress
542 response.setStatusCode(300);
543
544 segInit(processId, parameter);
545 }
546}
547
548void
549WriteHandle::extendNoEndTime(ProcessInfo& process)
550{
551 ndn::time::steady_clock::TimePoint& noEndTime = process.noEndTime;
552 ndn::time::steady_clock::TimePoint now = ndn::time::steady_clock::now();
553 RepoCommandResponse& response = process.response;
554 if (now > noEndTime) {
555 response.setStatusCode(405);
556 return;
557 }
558 //extends noEndTime
559 process.noEndTime =
560 ndn::time::steady_clock::now() + m_noEndTimeout;
561
562}
563
564void
565WriteHandle::negativeReply(const Interest& interest, int statusCode)
566{
567 RepoCommandResponse response;
568 response.setStatusCode(statusCode);
569 reply(interest, response);
570}
571
572} //namespace repo