blob: fa0ea4c3eee6868b093713c48c79f336f728125f [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 Afanasyev4d086752013-02-07 13:06:04 -080065 m_ccnx->clearInterestFilter (*it);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080066 }
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080067
68 m_prefixes.clear ();
Zhenkai Zhue42b4572013-01-22 15:57:54 -080069}
70
71void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080072ContentServer::registerPrefix(const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080073{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080074 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
75 // Format for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhub74e1e92013-01-25 14:36:18 -080076
Alexander Afanasyev4d086752013-02-07 13:06:04 -080077 _LOG_DEBUG (">> content server: register " << forwardingHint);
78 m_ccnx->setInterestFilter (forwardingHint, bind(&ContentServer::filterAndServe, this, forwardingHint, _1));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080079
80 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080081 m_prefixes.insert(forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080082}
83
84void
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080085ContentServer::deregisterPrefix (const Name &forwardingHint)
Zhenkai Zhue42b4572013-01-22 15:57:54 -080086{
Alexander Afanasyev4d086752013-02-07 13:06:04 -080087 _LOG_DEBUG ("<< content server: deregister " << forwardingHint);
88 m_ccnx->clearInterestFilter(forwardingHint);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080089
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -080090 ScopedLock lock (m_mutex);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -080091 m_prefixes.erase (forwardingHint);
Zhenkai Zhue42b4572013-01-22 15:57:54 -080092}
93
Alexander Afanasyev4d086752013-02-07 13:06:04 -080094void
95ContentServer::filterAndServe (Name forwardingHint, const Name &interest)
96{
97 // Format for files: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
98 // Format for actions: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Zhenkai Zhuc3a27872013-01-25 19:21:25 -080099
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800100 Name name = interest.getPartialName (forwardingHint.size());
101 // name for files: /<device_name>/<appname>/file/<hash>/<segment>
102 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
103
104 if (name.size() >= 4 && name.getCompFromBackAsString (3) == m_appName)
105 {
106 string type = name.getCompFromBackAsString (2);
107 if (type == "file")
108 {
109 serve_File (forwardingHint, interest);
110 }
111 else if (type == "action")
112 {
113 serve_Action (forwardingHint, interest);
114 }
115 }
116}
Zhenkai Zhuc3a27872013-01-25 19:21:25 -0800117
118void
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800119ContentServer::serve_Action (Name forwardingHint, Name interest)
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800120{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800121 _LOG_DEBUG (">> content server serving ACTION, hint: " << forwardingHint << ", interest: " << interest);
122 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_Action_Execute, this, forwardingHint, interest), boost::lexical_cast<string>(interest));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800123 // need to unlock ccnx mutex... or at least don't lock it
124}
125
126void
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800127ContentServer::serve_File (Name forwardingHint, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800128{
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800129 _LOG_DEBUG (">> content server serving FILE, hint: " << forwardingHint << ", interest: " << interest);
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800130
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800131 m_scheduler->scheduleOneTimeTask (m_scheduler, 0, bind (&ContentServer::serve_File_Execute, this, forwardingHint, interest), boost::lexical_cast<string>(interest));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800132 // need to unlock ccnx mutex... or at least don't lock it
133}
134
135void
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800136ContentServer::serve_File_Execute (Name forwardingHint, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800137{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800138 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800139 // interest: /<forwarding-hint>/<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800140
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800141 Name name = interest.getPartialName (forwardingHint.size());
142 // name: /<device_name>/<appname>/file/<hash>/<segment>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800143
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800144 int64_t segment = name.getCompFromBackAsInt (0);
145 Name deviceName = name.getPartialName (0, name.size () - 4);
146 Hash hash (head(name.getCompFromBack (1)), name.getCompFromBack (1).size());
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800147
148 _LOG_DEBUG (" server FILE for device: " << deviceName << ", file_hash: " << hash.shortHash () << " segment: " << segment);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800149
150 string hashStr = lexical_cast<string> (hash);
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800151
152 ObjectDbPtr db;
153
154 ScopedLock(m_dbCacheMutex);
155 {
156 DbCache::iterator it = m_dbCache.find(hash);
157 if (it != m_dbCache.end())
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800158 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800159 db = it->second;
160 }
161 else
162 {
163 if (ObjectDb::DoesExist (m_dbFolder, deviceName, hashStr)) // this is kind of overkill, as it counts available segments
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800164 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800165 db = boost::make_shared<ObjectDb>(m_dbFolder, hashStr);
166 m_dbCache.insert(make_pair(hash, db));
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800167 }
168 else
169 {
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800170 _LOG_ERROR ("ObjectDd doesn't exist for device: " << deviceName << ", file_hash: " << hash.shortHash ());
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800171 }
172 }
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800173 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800174
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800175 if (db)
176 {
177 BytesPtr co = db->fetchSegment (deviceName, segment);
178 if (co)
179 {
180 if (forwardingHint.size () == 0)
181 {
182 _LOG_DEBUG (ParsedContentObject (*co).name ());
183 m_ccnx->putToCcnd (*co);
184 }
185 else
186 {
187 if (m_freshness > 0)
188 {
189 m_ccnx->publishData(interest, *co, m_freshness);
190 }
191 else
192 {
193 m_ccnx->publishData(interest, *co);
194 }
195 }
196
197 }
198 else
199 {
200 _LOG_ERROR ("ObjectDd exists, but no segment " << segment << " for device: " << deviceName << ", file_hash: " << hash.shortHash ());
201 }
202
203 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800204}
205
206void
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800207ContentServer::serve_Action_Execute (Name forwardingHint, Name interest)
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800208{
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800209 // forwardingHint: /<forwarding-hint>
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800210 // interest: /<forwarding-hint>/<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800211
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800212 Name name = interest.getPartialName (forwardingHint.size());
213 // name for actions: /<device_name>/<appname>/action/<shared-folder>/<action-seq>
Alexander Afanasyev1d1cc832013-02-05 20:03:36 -0800214
Alexander Afanasyev4d086752013-02-07 13:06:04 -0800215 int64_t seqno = name.getCompFromBackAsInt (0);
216 Name deviceName = name.getPartialName (0, name.size () - 4);
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800217
218 _LOG_DEBUG (" server ACTION for device: " << deviceName << " and seqno: " << seqno);
219
220 PcoPtr pco = m_actionLog->LookupActionPco (deviceName, seqno);
221 if (pco)
222 {
223 if (forwardingHint.size () == 0)
224 {
225 m_ccnx->putToCcnd (pco->buf ());
226 }
227 else
228 {
229 const Bytes &content = pco->buf ();
230 if (m_freshness > 0)
Zhenkai Zhubc738572013-01-23 22:46:11 -0800231 {
232 m_ccnx->publishData(interest, content, m_freshness);
233 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800234 else
Zhenkai Zhubc738572013-01-23 22:46:11 -0800235 {
236 m_ccnx->publishData(interest, content);
237 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800238 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800239 }
Alexander Afanasyev28ca3ed2013-01-24 23:17:15 -0800240 else
241 {
242 _LOG_ERROR ("ACTION not found for device: " << deviceName << " and seqno: " << seqno);
243 }
Zhenkai Zhue42b4572013-01-22 15:57:54 -0800244}
Zhenkai Zhu92bb6952013-02-06 16:43:30 -0800245
246void
247ContentServer::flushStaleDbCache()
248{
249 ScopedLock(m_dbCacheMutex);
250 DbCache::iterator it = m_dbCache.begin();
251 while (it != m_dbCache.end())
252 {
253 ObjectDbPtr db = it->second;
254 if (db->secondsSinceLastUse() >= DB_CACHE_LIFETIME)
255 {
256 m_dbCache.erase(it++);
257 }
258 else
259 {
260 ++it;
261 }
262 }
263}