blob: 2aa19ca7402fa518ff6f2c1ec1461f2fe51ab680 [file] [log] [blame]
Zhenkai Zhue42b4572013-01-22 15:57:54 -08001/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil -*- */
2/*
3 * Copyright (c) 2013 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: Zhenkai Zhu <zhenkai@cs.ucla.edu>
19 * Alexander Afanasyev <alexander.afanasyev@ucla.edu>
20 */
21
22#include "content-server.h"
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080023#include "logging.h"
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080024#include <boost/make_shared.hpp>
25#include <utility>
26#include "task.h"
27#include "periodic-task.h"
28#include "simple-interval-generator.h"
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080029#include <boost/lexical_cast.hpp>
30
31INIT_LOGGER ("ContentServer");
Zhenkai Zhue42b4572013-01-22 15:57:54 -080032
33using namespace Ccnx;
34using namespace std;
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080035using namespace boost;
Zhenkai Zhue42b4572013-01-22 15:57:54 -080036
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080037static const int DB_CACHE_LIFETIME = 60;
38
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080039ContentServer::ContentServer(CcnxWrapperPtr ccnx, ActionLogPtr actionLog,
40 const boost::filesystem::path &rootDir,
41 const Ccnx::Name &deviceName, const std::string &sharedFolderName,
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080042 const std::string &appName,
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080043 int freshness)
44 : m_ccnx(ccnx)
45 , m_actionLog(actionLog)
46 , m_dbFolder(rootDir / ".chronoshare")
47 , m_freshness(freshness)
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080048 , m_scheduler (new Scheduler())
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080049 , m_deviceName (deviceName)
50 , m_sharedFolderName (sharedFolderName)
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080051 , m_appName (appName)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080052{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080053 m_scheduler->start ();
54 TaskPtr flushStaleDbCacheTask = boost::make_shared<PeriodicTask>(boost::bind(&ContentServer::flushStaleDbCache, this), "flush-state-db-cache", m_scheduler, boost::make_shared<SimpleIntervalGenerator>(DB_CACHE_LIFETIME));
55 m_scheduler->addTask(flushStaleDbCacheTask);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080056}
57
58ContentServer::~ContentServer()
59{
Zhenkai Zhu92bb6952013-02-06 16:43:30 -080060 m_scheduler->shutdown ();
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080061
62 ScopedLock lock (m_mutex);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080063 for (PrefixIt it = m_prefixes.begin(); it != m_prefixes.end(); ++it)
64 {
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080065 Name filePrefix = Name (*it)(m_appName)("file");
66 Name actionPrefix = Name (*it)(m_appName)(m_sharedFolderName)("action");
67
68 m_ccnx->clearInterestFilter(filePrefix);
69 m_ccnx->clearInterestFilter(actionPrefix);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080070 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080071
72 m_prefixes.clear ();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080073}
74
75void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080076ContentServer::registerPrefix(const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080077{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080078 // Format for files: /<forwarding-hint>/<appname>/file/<hash>/<device_name>/<segment>
79 // Format for actions: /<forwarding-hint>/<appname>/<shared-folder>/action/<device_name>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080080
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080081 Name filePrefix = Name (forwardingHint)(m_appName)("file");
82 Name actionPrefix = Name (forwardingHint)(m_appName)(m_sharedFolderName)("action");
83
84 m_ccnx->setInterestFilter (filePrefix, bind(&ContentServer::serve_File, this, forwardingHint, filePrefix, _1));
85 m_ccnx->setInterestFilter (actionPrefix, bind(&ContentServer::serve_Action, this, forwardingHint, actionPrefix, _1));
86
87 _LOG_DEBUG (">> content server: register FILE " << filePrefix);
88 _LOG_DEBUG (">> content server: register ACTION " << actionPrefix);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080089
90 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080091 m_prefixes.insert(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080092}
93
94void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080095ContentServer::deregisterPrefix (const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080096{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080097 Name filePrefix = Name (forwardingHint)(m_appName)("file");
98 Name actionPrefix = Name (forwardingHint)(m_appName)(m_sharedFolderName)("action");
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080099
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800100 m_ccnx->clearInterestFilter(filePrefix);
101 m_ccnx->clearInterestFilter(actionPrefix);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800102
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800103 _LOG_DEBUG ("<< content server: deregister FILE " << filePrefix);
104 _LOG_DEBUG ("<< content server: deregister ACTION " << actionPrefix);
105
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800106 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800107 m_prefixes.erase (forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800108}
109
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800110// void
111// ContentServer::serve(Name forwardingHint, const Name &interest)
112// {
113// // /forwardingHint/app-name/device-name/action/shared-folder/action-seq
114// // /forwardingHint/app-name/device-name/file/file-hash/segment
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800115
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800116// Name name = interest.getPartialName(forwardingHint.size());
117// if (name.size() > 3)
118// {
119// string type = name.getCompAsString(name.size() - 3);
120// if (type == "action")
121// {
122// serve_Action (forwardingHint, interest);
123// }
124// else if (type == "file")
125// {
126// serve_File (forwardingHint, interest);
127// }
128// }
129// }
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800130
131void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800132ContentServer::serve_Action (Name forwardingHint, Name locatorPrefix, Name interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800133{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800134 _LOG_DEBUG (">> content server serving ACTION, hint: " << forwardingHint << ", locatorPrefix: " << locatorPrefix << ", interest: " << interest);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800135 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_Action_Execute, this, forwardingHint, locatorPrefix, interest), boost::lexical_cast<string>(interest));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800136 // need to unlock ccnx mutex... or at least don't lock it
137}
138
139void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800140ContentServer::serve_File (Name forwardingHint, Name locatorPrefix, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800141{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800142 _LOG_DEBUG (">> content server serving FILE, hint: " << forwardingHint << ", locatorPrefix: " << locatorPrefix << ", interest: " << interest);
143
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800144 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_File_Execute, this, forwardingHint, locatorPrefix, interest), boost::lexical_cast<string>(interest));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800145 // need to unlock ccnx mutex... or at least don't lock it
146}
147
148void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800149ContentServer::serve_File_Execute (Name forwardingHint, Name locatorPrefix, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800150{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800151 // forwardingHint: /<forwarding-hint>
152 // locatorPrefix: /<forwarding-hint>/<appname>/file
153 // interest: /<forwarding-hint>/<appname>/file/<hash>/<device_name>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800154
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800155 Name pureInterest = interest.getPartialName (locatorPrefix.size ());
156 // pureInterest: /<hash>/<device_name>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800157
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800158 int64_t segment = pureInterest.getCompFromBackAsInt (0);
159 Name deviceName = pureInterest.getPartialName (1, pureInterest.size () - 2);
160 Hash hash (head(pureInterest.getComp (0)), pureInterest.getComp (0).size());
161
162 _LOG_DEBUG (" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash () << " segment: " << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800163
164 string hashStr = lexical_cast<string> (hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800165
166 ObjectDbPtr db;
167
168 ScopedLock(m_dbCacheMutex);
169 {
170 DbCache::iterator it = m_dbCache.find(hash);
171 if (it != m_dbCache.end())
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800172 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800173 db = it->second;
174 }
175 else
176 {
177 if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800178 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800179 db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
180 m_dbCache.insert(make_pair(hash, db));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800181 }
182 else
183 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800184 _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800185 }
186 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800187 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800188
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800189 if (db)
190 {
191 BytesPtr co = db->fetchSegment (deviceName, segment);
192 if (co)
193 {
194 if (forwardingHint.size () == 0)
195 {
196 _LOG_DEBUG (ParsedContentObject (*co).name ());
197 m_ccnx->putToCcnd (*co);
198 }
199 else
200 {
201 if (m_freshness > 0)
202 {
203 m_ccnx->publishData(interest, *co, m_freshness);
204 }
205 else
206 {
207 m_ccnx->publishData(interest, *co);
208 }
209 }
210
211 }
212 else
213 {
214 _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
215 }
216
217 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800218}
219
220void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800221ContentServer::serve_Action_Execute (Name forwardingHint, Name locatorPrefix, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800222{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800223 // forwardingHint: /<forwarding-hint>
224 // locatorPrefix: /<forwarding-hint>/<appname>/<shared-folder>/action
225 // interest: /<forwarding-hint>/<appname>/<shared-folder>/action/<device_name>/<action-seq>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800226
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800227 Name pureInterest = interest.getPartialName (locatorPrefix.size ());
228 // pureInterest: /<device_name>/<action-seq>
229
230 int64_t seqno = pureInterest.getCompFromBackAsInt (0);
231 Name deviceName = pureInterest.getPartialName (0, pureInterest.size () - 1);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800232
233 _LOG_DEBUG (" server ACTION for device: " << deviceName << " and seqno: " << seqno);
234
235 PcoPtr pco = m_actionLog->LookupActionPco (deviceName, seqno);
236 if (pco)
237 {
238 if (forwardingHint.size () == 0)
239 {
240 m_ccnx->putToCcnd (pco->buf ());
241 }
242 else
243 {
244 const Bytes &content = pco->buf ();
245 if (m_freshness > 0)
Zhenkai Zhubc738572013-01-23 22:46:11 -0800246 {
247 m_ccnx->publishData(interest, content, m_freshness);
248 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800249 else
Zhenkai Zhubc738572013-01-23 22:46:11 -0800250 {
251 m_ccnx->publishData(interest, content);
252 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800253 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800254 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800255 else
256 {
257 _LOG_ERROR ("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
258 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800259}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800260
261void
262ContentServer::flushStaleDbCache()
263{
264 ScopedLock(m_dbCacheMutex);
265 DbCache::iterator it = m_dbCache.begin();
266 while (it != m_dbCache.end())
267 {
268 ObjectDbPtr db = it->second;
269 if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME)
270 {
271 m_dbCache.erase(it++);
272 }
273 else
274 {
275 ++it;
276 }
277 }
278}