CernVM-FS  2.12.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
talk.cc
Go to the documentation of this file.
1 
15 #ifndef __STDC_FORMAT_MACROS
16 #define __STDC_FORMAT_MACROS
17 #endif
18 
19 #include "cvmfs_config.h"
20 #include "talk.h"
21 
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <pthread.h>
25 #include <stdint.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <sys/types.h>
29 #include <sys/uio.h>
30 #include <sys/un.h>
31 #include <unistd.h>
32 
33 #include <cassert>
34 #include <cstdlib>
35 #include <cstring>
36 #include <string>
37 #include <vector>
38 
39 #include "cache.h"
40 #include "cache_posix.h"
41 #include "catalog_mgr_client.h"
42 #include "cvmfs.h"
43 #include "duplex_sqlite3.h"
44 #include "fuse_remount.h"
45 #include "glue_buffer.h"
46 #include "loader.h"
47 #include "monitor.h"
48 #include "mountpoint.h"
49 #include "network/download.h"
50 #include "nfs_maps.h"
51 #include "options.h"
52 #include "quota.h"
53 #include "shortstring.h"
54 #include "statistics.h"
55 #include "tracer.h"
56 #include "util/logging.h"
57 #include "util/platform.h"
58 #include "util/pointer.h"
59 #include "wpad.h"
60 
61 using namespace std; // NOLINT
62 
63 
64 void TalkManager::Answer(int con_fd, const string &msg) {
65  (void)send(con_fd, &msg[0], msg.length(), MSG_NOSIGNAL);
66 }
67 
68 
69 void TalkManager::AnswerStringList(int con_fd, const vector<string> &list) {
70  string list_str;
71  for (unsigned i = 0; i < list.size(); ++i) {
72  list_str += list[i] + "\n";
73  }
74  Answer(con_fd, list_str);
75 }
76 
77 
79  const string &socket_path,
80  MountPoint *mount_point,
81  FuseRemounter *remounter)
82 {
84  talk_manager(new TalkManager(socket_path, mount_point, remounter));
85 
86  talk_manager->socket_fd_ = MakeSocket(socket_path, 0660);
87  if (talk_manager->socket_fd_ == -1)
88  return NULL;
89  if (listen(talk_manager->socket_fd_, 1) == -1)
90  return NULL;
91 
92  LogCvmfs(kLogTalk, kLogDebug, "socket created at %s (fd %d)",
93  socket_path.c_str(), talk_manager->socket_fd_);
94 
95  return talk_manager.Release();
96 }
97 
98 
100  vector<string> host_chain;
101  vector<int> rtt;
102  unsigned active_host;
103 
104  download_mgr->GetHostInfo(&host_chain, &rtt, &active_host);
105  if (host_chain.size() == 0)
106  return "No hosts defined\n";
107 
108  string host_str;
109  for (unsigned i = 0; i < host_chain.size(); ++i) {
110  host_str += " [" + StringifyInt(i) + "] " + host_chain[i] + " (";
112  host_str += "unprobed";
113  else if (rtt[i] == download::DownloadManager::kProbeDown)
114  host_str += "host down";
115  else if (rtt[i] == download::DownloadManager::kProbeGeo)
116  host_str += "geographically ordered";
117  else
118  host_str += StringifyInt(rtt[i]) + " ms";
119  host_str += ")\n";
120  }
121  host_str += "Active host " + StringifyInt(active_host) + ": " +
122  host_chain[active_host] + "\n";
123  return host_str;
124 }
125 
127  vector< vector<download::DownloadManager::ProxyInfo> > proxy_chain;
128  unsigned active_group;
129  unsigned fallback_group;
130 
131  download_mgr->GetProxyInfo(&proxy_chain, &active_group, &fallback_group);
132  string proxy_str;
133  if (proxy_chain.size()) {
134  proxy_str += "Load-balance groups:\n";
135  for (unsigned i = 0; i < proxy_chain.size(); ++i) {
136  vector<string> urls;
137  for (unsigned j = 0; j < proxy_chain[i].size(); ++j) {
138  urls.push_back(proxy_chain[i][j].Print());
139  }
140  proxy_str +=
141  "[" + StringifyInt(i) + "] " + JoinStrings(urls, ", ") + "\n";
142  }
143  proxy_str += "Active proxy: [" + StringifyInt(active_group) + "] " +
144  proxy_chain[active_group][0].url + "\n";
145  if (fallback_group < proxy_chain.size())
146  proxy_str += "First fallback group: [" +
147  StringifyInt(fallback_group) + "]\n";
148  } else {
149  proxy_str = "No proxies defined\n";
150  }
151  return proxy_str;
152 }
153 
154 
159 void *TalkManager::MainResponder(void *data) {
160  TalkManager *talk_mgr = reinterpret_cast<TalkManager *>(data);
161  MountPoint *mount_point = talk_mgr->mount_point_;
162  FileSystem *file_system = mount_point->file_system();
163  FuseRemounter *remounter = talk_mgr->remounter_;
164  LogCvmfs(kLogTalk, kLogDebug, "talk thread started");
165 
166  struct sockaddr_un remote;
167  socklen_t socket_size = sizeof(remote);
168  int con_fd = -1;
169  while (true) {
170  if (con_fd >= 0) {
171  shutdown(con_fd, SHUT_RDWR);
172  close(con_fd);
173  }
174  LogCvmfs(kLogTalk, kLogDebug, "accepting connections on socketfd %d",
175  talk_mgr->socket_fd_);
176  if ((con_fd = accept(talk_mgr->socket_fd_,
177  (struct sockaddr *)&remote,
178  &socket_size)) < 0)
179  {
180  LogCvmfs(kLogTalk, kLogDebug, "terminating talk thread (fd %d, errno %d)",
181  con_fd, errno);
182  break;
183  }
184 
185  char buf[kMaxCommandSize];
186  int bytes_read;
187  if ((bytes_read = recv(con_fd, buf, sizeof(buf), 0)) <= 0)
188  continue;
189 
190  if (buf[bytes_read-1] == '\0')
191  bytes_read--;
192  const string line = string(buf, bytes_read);
193  LogCvmfs(kLogTalk, kLogDebug, "received %s (length %lu)",
194  line.c_str(), line.length());
195 
196  if (line == "tracebuffer flush") {
197  mount_point->tracer()->Flush();
198  talk_mgr->Answer(con_fd, "OK\n");
199  } else if (line == "cache size") {
200  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
202  talk_mgr->Answer(con_fd, "Cache cannot report its size\n");
203  } else {
204  uint64_t size_unpinned = quota_mgr->GetSize();
205  uint64_t size_pinned = quota_mgr->GetSizePinned();
206  const string size_str = "Current cache size is " +
207  StringifyInt(size_unpinned / (1024*1024)) + "MB (" +
208  StringifyInt(size_unpinned) + " Bytes), pinned: " +
209  StringifyInt(size_pinned / (1024*1024)) + "MB (" +
210  StringifyInt(size_pinned) + " Bytes)\n";
211  talk_mgr->Answer(con_fd, size_str);
212  }
213  } else if (line == "cache instance") {
214  talk_mgr->Answer(con_fd, file_system->cache_mgr()->Describe());
215  } else if (line == "cache list") {
216  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
217  if (!quota_mgr->HasCapability(QuotaManager::kCapList)) {
218  talk_mgr->Answer(con_fd, "Cache cannot list its entries\n");
219  } else {
220  vector<string> ls = quota_mgr->List();
221  talk_mgr->AnswerStringList(con_fd, ls);
222  }
223  } else if (line == "cache list pinned") {
224  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
225  if (!quota_mgr->HasCapability(QuotaManager::kCapList)) {
226  talk_mgr->Answer(con_fd, "Cache cannot list its entries\n");
227  } else {
228  vector<string> ls_pinned = quota_mgr->ListPinned();
229  talk_mgr->AnswerStringList(con_fd, ls_pinned);
230  }
231  } else if (line == "cache list catalogs") {
232  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
233  if (!quota_mgr->HasCapability(QuotaManager::kCapList)) {
234  talk_mgr->Answer(con_fd, "Cache cannot list its entries\n");
235  } else {
236  vector<string> ls_catalogs = quota_mgr->ListCatalogs();
237  talk_mgr->AnswerStringList(con_fd, ls_catalogs);
238  }
239  } else if (line.substr(0, 12) == "cleanup rate") {
240  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
242  talk_mgr->Answer(con_fd, "Unsupported by this cache\n");
243  } else {
244  if (line.length() < 14) {
245  talk_mgr->Answer(con_fd, "Usage: cleanup rate <period in mn>\n");
246  } else {
247  const uint64_t period_s = String2Uint64(line.substr(13)) * 60;
248  const uint64_t rate = quota_mgr->GetCleanupRate(period_s);
249  talk_mgr->Answer(con_fd, StringifyInt(rate) + "\n");
250  }
251  }
252  } else if (line.substr(0, 7) == "cleanup") {
253  QuotaManager *quota_mgr = file_system->cache_mgr()->quota_mgr();
254  if (!quota_mgr->HasCapability(QuotaManager::kCapShrink)) {
255  talk_mgr->Answer(con_fd, "Cache cannot trigger eviction\n");
256  } else {
257  if (line.length() < 9) {
258  talk_mgr->Answer(con_fd, "Usage: cleanup <MB>\n");
259  } else {
260  const uint64_t size = String2Uint64(line.substr(8))*1024*1024;
261  if (quota_mgr->Cleanup(size)) {
262  talk_mgr->Answer(con_fd, "OK\n");
263  } else {
264  talk_mgr->Answer(con_fd, "Not fully cleaned "
265  "(there might be pinned chunks)\n");
266  }
267  }
268  }
269  } else if (line.substr(0, 5) == "evict") {
270  assert(mount_point->file_system()->type() == FileSystem::kFsFuse);
271  if (line.length() < 7) {
272  talk_mgr->Answer(con_fd, "Usage: evict <path>\n");
273  } else {
274  const string path = line.substr(6);
275  const bool found_regular = cvmfs::Evict(path);
276  if (found_regular)
277  talk_mgr->Answer(con_fd, "OK\n");
278  else
279  talk_mgr->Answer(con_fd, "No such regular file\n");
280  }
281  } else if (line.substr(0, 3) == "pin") {
282  assert(mount_point->file_system()->type() == FileSystem::kFsFuse);
283  if (line.length() < 5) {
284  talk_mgr->Answer(con_fd, "Usage: pin <path>\n");
285  } else {
286  const string path = line.substr(4);
287  const bool found_regular = cvmfs::Pin(path);
288  if (found_regular)
289  talk_mgr->Answer(con_fd, "OK\n");
290  else
291  talk_mgr->Answer(con_fd, "No such regular file or pinning failed\n");
292  }
293  } else if (line == "mountpoint") {
294  talk_mgr->Answer(con_fd, cvmfs::loader_exports_->mount_point + "\n");
295  } else if (line == "device id") {
296  if (cvmfs::loader_exports_->version >= 5)
297  talk_mgr->Answer(con_fd, cvmfs::loader_exports_->device_id + "\n");
298  else
299  talk_mgr->Answer(con_fd, "0:0\n");
300  } else if (line.substr(0, 13) == "send mount fd") {
301  // Hidden command intended to be used only by the cvmfs mount helper
302  if (line.length() < 15) {
303  talk_mgr->Answer(con_fd, "EINVAL\n");
304  } else {
305  std::string socket_path = line.substr(14);
306  bool retval = cvmfs::SendFuseFd(socket_path);
307  talk_mgr->Answer(con_fd, retval ? "OK\n" : "Failed\n");
309  "Attempt to send fuse connection info to new mount (via %s)%s",
310  socket_path.c_str(), retval ? "" : " -- failed!");
311  }
312  } else if (line.substr(0, 7) == "remount") {
313  FuseRemounter::Status status;
314  if (line == "remount sync")
315  status = remounter->CheckSynchronously();
316  else
317  status = remounter->Check();
318  switch (status) {
320  talk_mgr->Answer(con_fd, "Failed\n");
321  break;
323  talk_mgr->Answer(con_fd, "Failed (no space)\n");
324  break;
326  talk_mgr->Answer(con_fd, "Catalog up to date\n");
327  break;
329  talk_mgr->Answer(con_fd, "New revision applied\n");
330  break;
332  talk_mgr->Answer(con_fd, "In maintenance mode\n");
333  break;
334  default:
335  talk_mgr->Answer(con_fd, "internal error\n");
336  }
337  } else if (line.substr(0, 6) == "chroot") {
338  if (line.length() < 8) {
339  talk_mgr->Answer(con_fd, "Usage: chroot <hash>\n");
340  } else {
341  std::string root_hash = Trim(line.substr(7), true /* trim_newline */);
342  FuseRemounter::Status status = remounter->ChangeRoot(
344  switch (status) {
346  talk_mgr->Answer(con_fd, "OK\n");
347  break;
348  default:
349  talk_mgr->Answer(con_fd, "Failed\n");
350  break;
351  }
352  }
353  } else if (line == "detach nested catalogs") {
354  mount_point->catalog_mgr()->DetachNested();
355  talk_mgr->Answer(con_fd, "OK\n");
356  } else if (line == "revision") {
357  string revision = StringifyInt(mount_point->catalog_mgr()->GetRevision());
358  talk_mgr->Answer(con_fd, revision + "\n");
359  } else if (line == "max ttl info") {
360  const unsigned max_ttl = mount_point->GetMaxTtlMn();
361  if (max_ttl == 0) {
362  talk_mgr->Answer(con_fd, "unset\n");
363  } else {
364  const string max_ttl_str = StringifyInt(max_ttl) + " minutes\n";
365  talk_mgr->Answer(con_fd, max_ttl_str);
366  }
367  } else if (line.substr(0, 11) == "max ttl set") {
368  if (line.length() < 13) {
369  talk_mgr->Answer(con_fd, "Usage: max ttl set <minutes>\n");
370  } else {
371  const unsigned max_ttl = String2Uint64(line.substr(12));
372  mount_point->SetMaxTtlMn(max_ttl);
373  talk_mgr->Answer(con_fd, "OK\n");
374  }
375  } else if (line.substr(0, 14) == "nameserver get") {
376  const string dns_server = mount_point->download_mgr()->GetDnsServer();
377  const string reply = !dns_server.empty() ?
378  std::string("DNS server address: ") + dns_server + "\n":
379  std::string("DNS server not set.\n");
380  talk_mgr->Answer(con_fd, reply);
381  } else if (line.substr(0, 14) == "nameserver set") {
382  if (line.length() < 16) {
383  talk_mgr->Answer(con_fd, "Usage: nameserver set <host>\n");
384  } else {
385  const string host = line.substr(15);
386  mount_point->download_mgr()->SetDnsServer(host);
387  talk_mgr->Answer(con_fd, "OK\n");
388  }
389  } else if (line == "external host info") {
390  string external_host_info =
391  talk_mgr->FormatHostInfo(mount_point->external_download_mgr());
392  talk_mgr->Answer(con_fd, external_host_info);
393  } else if (line == "host info") {
394  string host_info = talk_mgr->FormatHostInfo(mount_point->download_mgr());
395  talk_mgr->Answer(con_fd, host_info);
396  } else if (line == "host probe") {
397  mount_point->download_mgr()->ProbeHosts();
398  talk_mgr->Answer(con_fd, "OK\n");
399  } else if (line == "host probe geo") {
400  bool retval = mount_point->download_mgr()->ProbeGeo();
401  if (retval)
402  talk_mgr->Answer(con_fd, "OK\n");
403  else
404  talk_mgr->Answer(con_fd, "Failed\n");
405  } else if (line == "external host switch") {
406  mount_point->external_download_mgr()->SwitchHost();
407  talk_mgr->Answer(con_fd, "OK\n");
408  } else if (line == "host switch") {
409  mount_point->download_mgr()->SwitchHost();
410  talk_mgr->Answer(con_fd, "OK\n");
411  } else if (line.substr(0, 17) == "external host set") {
412  if (line.length() < 19) {
413  talk_mgr->Answer(con_fd, "Usage: external host set <URL>\n");
414  } else {
415  const std::string host = line.substr(18);
416  mount_point->external_download_mgr()->SetHostChain(host);
417  talk_mgr->Answer(con_fd, "OK\n");
418  }
419  } else if (line.substr(0, 8) == "host set") {
420  if (line.length() < 10) {
421  talk_mgr->Answer(con_fd, "Usage: host set <host list>\n");
422  } else {
423  const string hosts = line.substr(9);
424  mount_point->download_mgr()->SetHostChain(hosts);
425  talk_mgr->Answer(con_fd, "OK\n");
426  }
427  } else if (line == "external proxy info") {
428  string external_proxy_info =
429  talk_mgr->FormatProxyInfo(mount_point->external_download_mgr());
430  talk_mgr->Answer(con_fd, external_proxy_info);
431  } else if (line == "proxy info") {
432  string proxy_info =
433  talk_mgr->FormatProxyInfo(mount_point->download_mgr());
434  talk_mgr->Answer(con_fd, proxy_info);
435  } else if (line == "proxy rebalance") {
436  mount_point->download_mgr()->RebalanceProxies();
437  talk_mgr->Answer(con_fd, "OK\n");
438  } else if (line == "proxy group switch") {
439  mount_point->download_mgr()->SwitchProxyGroup();
440  talk_mgr->Answer(con_fd, "OK\n");
441  } else if (line.substr(0, 18) == "external proxy set") {
442  if (line.length() < 20) {
443  talk_mgr->Answer(con_fd, "Usage: external proxy set <proxy list>\n");
444  } else {
445  string external_proxies = line.substr(19);
446  mount_point->external_download_mgr()->SetProxyChain(
447  external_proxies, "", download::DownloadManager::kSetProxyRegular);
448  talk_mgr->Answer(con_fd, "OK\n");
449  }
450  } else if (line.substr(0, 9) == "proxy set") {
451  if (line.length() < 11) {
452  talk_mgr->Answer(con_fd, "Usage: proxy set <proxy list>\n");
453  } else {
454  string proxies = line.substr(10);
455  proxies =
457  mount_point->download_mgr());
458  if (proxies == "") {
459  talk_mgr->Answer(con_fd, "Failed, no valid proxies\n");
460  } else {
461  mount_point->download_mgr()->SetProxyChain(
463  talk_mgr->Answer(con_fd, "OK\n");
464  }
465  }
466  } else if (line.substr(0, 14) == "proxy fallback") {
467  if (line.length() < 15) {
468  talk_mgr->Answer(con_fd, "Usage: proxy fallback <proxy list>\n");
469  } else {
470  string fallback_proxies = line.substr(15);
471  mount_point->download_mgr()->SetProxyChain(
472  "", fallback_proxies, download::DownloadManager::kSetProxyFallback);
473  talk_mgr->Answer(con_fd, "OK\n");
474  }
475  } else if (line == "timeout info") {
476  unsigned timeout;
477  unsigned timeout_direct;
478  mount_point->download_mgr()->GetTimeout(&timeout, &timeout_direct);
479  string timeout_str = "Timeout with proxy: ";
480  if (timeout)
481  timeout_str += StringifyInt(timeout) + "s\n";
482  else
483  timeout_str += "no timeout\n";
484  timeout_str += "Timeout without proxy: ";
485  if (timeout_direct)
486  timeout_str += StringifyInt(timeout_direct) + "s\n";
487  else
488  timeout_str += "no timeout\n";
489  talk_mgr->Answer(con_fd, timeout_str);
490  } else if (line.substr(0, 11) == "timeout set") {
491  if (line.length() < 13) {
492  talk_mgr->Answer(con_fd, "Usage: timeout set <proxy> <direct>\n");
493  } else {
494  uint64_t timeout;
495  uint64_t timeout_direct;
496  String2Uint64Pair(line.substr(12), &timeout, &timeout_direct);
497  mount_point->download_mgr()->SetTimeout(timeout, timeout_direct);
498  talk_mgr->Answer(con_fd, "OK\n");
499  }
500  } else if (line == "open catalogs") {
501  talk_mgr->Answer(con_fd, mount_point->catalog_mgr()->PrintHierarchy());
502  } else if (line == "internal affairs") {
503  int current;
504  int highwater;
505  string result;
506 
507  result += "Inode Generation:\n " + cvmfs::PrintInodeGeneration();
508 
509  // Manually setting the values of the ShortString counters
510  mount_point->statistics()->Lookup("pathstring.n_instances")->
512  mount_point->statistics()->Lookup("pathstring.n_overflows")->
514  mount_point->statistics()->Lookup("namestring.n_instances")->
516  mount_point->statistics()->Lookup("namestring.n_overflows")->
518  mount_point->statistics()->Lookup("linkstring.n_instances")->
520  mount_point->statistics()->Lookup("linkstring.n_overflows")->
522 
523  // Manually setting the inode tracker numbers
524  glue::InodeTracker::Statistics inode_stats =
525  mount_point->inode_tracker()->GetStatistics();
526  glue::DentryTracker::Statistics dentry_stats =
527  mount_point->dentry_tracker()->GetStatistics();
528  glue::PageCacheTracker::Statistics page_cache_stats =
529  mount_point->page_cache_tracker()->GetStatistics();
530  mount_point->statistics()->Lookup("inode_tracker.n_insert")->Set(
531  atomic_read64(&inode_stats.num_inserts));
532  mount_point->statistics()->Lookup("inode_tracker.n_remove")->Set(
533  atomic_read64(&inode_stats.num_removes));
534  mount_point->statistics()->Lookup("inode_tracker.no_reference")->Set(
535  atomic_read64(&inode_stats.num_references));
536  mount_point->statistics()->Lookup("inode_tracker.n_hit_inode")->Set(
537  atomic_read64(&inode_stats.num_hits_inode));
538  mount_point->statistics()->Lookup("inode_tracker.n_hit_path")->Set(
539  atomic_read64(&inode_stats.num_hits_path));
540  mount_point->statistics()->Lookup("inode_tracker.n_miss_path")->Set(
541  atomic_read64(&inode_stats.num_misses_path));
542  mount_point->statistics()->Lookup("dentry_tracker.n_insert")->Set(
543  dentry_stats.num_insert);
544  mount_point->statistics()->Lookup("dentry_tracker.n_remove")->Set(
545  dentry_stats.num_remove);
546  mount_point->statistics()->Lookup("dentry_tracker.n_prune")->Set(
547  dentry_stats.num_prune);
548  mount_point->statistics()->Lookup("page_cache_tracker.n_insert")->Set(
549  page_cache_stats.n_insert);
550  mount_point->statistics()->Lookup("page_cache_tracker.n_remove")->Set(
551  page_cache_stats.n_remove);
552  mount_point->statistics()->Lookup("page_cache_tracker.n_open_direct")->
553  Set(page_cache_stats.n_open_direct);
554  mount_point->statistics()->Lookup("page_cache_tracker.n_open_flush")->
555  Set(page_cache_stats.n_open_flush);
556  mount_point->statistics()->Lookup("page_cache_tracker.n_open_cached")->
557  Set(page_cache_stats.n_open_cached);
558 
559  if (file_system->cache_mgr()->id() == kPosixCacheManager) {
560  PosixCacheManager *cache_mgr =
561  reinterpret_cast<PosixCacheManager *>(
562  file_system->cache_mgr());
563  result += "\nCache Mode: ";
564  switch (cache_mgr->cache_mode()) {
566  result += "read-write";
567  break;
569  result += "read-only";
570  break;
571  default:
572  result += "unknown";
573  }
574  }
575  bool drainout_mode;
576  bool maintenance_mode;
577  cvmfs::GetReloadStatus(&drainout_mode, &maintenance_mode);
578  result += "\nDrainout Mode: " + StringifyBool(drainout_mode) + "\n";
579  result += "Maintenance Mode: " + StringifyBool(maintenance_mode) + "\n";
580 
581  if (file_system->IsNfsSource()) {
582  result += "\nNFS Map Statistics:\n";
583  result += file_system->nfs_maps()->GetStatistics();
584  }
585 
586  result += "SQlite Statistics:\n";
587  sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &current, &highwater, 0);
588  result += " Number of allocations " + StringifyInt(current) + "\n";
589 
590  sqlite3_status(SQLITE_STATUS_MEMORY_USED, &current, &highwater, 0);
591  result += " General purpose allocator " +StringifyInt(current/1024) +
592  " KB / " + StringifyInt(highwater/1024) + " KB\n";
593 
594  sqlite3_status(SQLITE_STATUS_MALLOC_SIZE, &current, &highwater, 0);
595  result += " Largest malloc " + StringifyInt(highwater) + " Bytes\n";
596 
597  sqlite3_status(SQLITE_STATUS_PAGECACHE_USED, &current, &highwater, 0);
598  result += " Page cache allocations " + StringifyInt(current) + " / " +
599  StringifyInt(highwater) + "\n";
600 
601  sqlite3_status(SQLITE_STATUS_PAGECACHE_OVERFLOW,
602  &current, &highwater, 0);
603  result += " Page cache overflows " + StringifyInt(current/1024) +
604  " KB / " + StringifyInt(highwater/1024) + " KB\n";
605 
606  sqlite3_status(SQLITE_STATUS_PAGECACHE_SIZE, &current, &highwater, 0);
607  result += " Largest page cache allocation " + StringifyInt(highwater) +
608  " Bytes\n";
609 
610  sqlite3_status(SQLITE_STATUS_SCRATCH_USED, &current, &highwater, 0);
611  result += " Scratch allocations " + StringifyInt(current) + " / " +
612  StringifyInt(highwater) + "\n";
613 
614  sqlite3_status(SQLITE_STATUS_SCRATCH_OVERFLOW, &current, &highwater, 0);
615  result += " Scratch overflows " + StringifyInt(current) + " / " +
616  StringifyInt(highwater) + "\n";
617 
618  sqlite3_status(SQLITE_STATUS_SCRATCH_SIZE, &current, &highwater, 0);
619  result += " Largest scratch allocation " + StringifyInt(highwater/1024)
620  + " KB\n";
621 
622  result += "\nPer-Connection Memory Statistics:\n" +
623  mount_point->catalog_mgr()->PrintAllMemStatistics();
624 
625  result += "\nLatency distribution of system calls:\n";
626 
627  result += "Lookup\n" + file_system->hist_fs_lookup()->ToString();
628  result += "Forget\n" + file_system->hist_fs_forget()->ToString();
629  result += "Multi-Forget\n"
630  + file_system->hist_fs_forget_multi()->ToString();
631  result += "Getattr\n" + file_system->hist_fs_getattr()->ToString();
632  result += "Readlink\n" + file_system->hist_fs_readlink()->ToString();
633  result += "Opendir\n" + file_system->hist_fs_opendir()->ToString();
634  result += "Releasedir\n" + file_system->hist_fs_releasedir()->ToString();
635  result += "Readdir\n" + file_system->hist_fs_readdir()->ToString();
636  result += "Open\n" + file_system->hist_fs_open()->ToString();
637  result += "Read\n" + file_system->hist_fs_read()->ToString();
638  result += "Release\n" + file_system->hist_fs_release()->ToString();
639 
640  result += "\nRaw Counters:\n" +
642 
643  talk_mgr->Answer(con_fd, result);
644  } else if (line == "reset error counters") {
645  file_system->ResetErrorCounters();
646  talk_mgr->Answer(con_fd, "OK\n");
647  } else if (line == "pid") {
648  const string pid_str = StringifyInt(cvmfs::pid_) + "\n";
649  talk_mgr->Answer(con_fd, pid_str);
650  } else if (line == "pid cachemgr") {
651  const string pid_str =
652  StringifyInt(file_system->cache_mgr()->quota_mgr()->GetPid()) + "\n";
653  talk_mgr->Answer(con_fd, pid_str);
654  } else if (line == "pid watchdog") {
655  const string pid_str = StringifyInt(Watchdog::GetPid()) + "\n";
656  talk_mgr->Answer(con_fd, pid_str);
657  } else if (line == "parameters") {
658  talk_mgr->Answer(con_fd, file_system->options_mgr()->Dump());
659  } else if (line == "hotpatch history") {
660  string history_str =
661  StringifyTime(cvmfs::loader_exports_->boot_time, true) +
662  " (start of CernVM-FS loader " +
664  for (loader::EventList::const_iterator i =
666  iEnd = cvmfs::loader_exports_->history.end(); i != iEnd; ++i)
667  {
668  history_str += StringifyTime((*i)->timestamp, true) +
669  " (loaded CernVM-FS Fuse Module " +
670  (*i)->so_version + ")\n";
671  }
672  talk_mgr->Answer(con_fd, history_str);
673  } else if (line == "vfs inodes") {
674  string result;
676  mount_point->inode_tracker()->BeginEnumerate());
677  uint64_t inode;
678  while (mount_point->inode_tracker()->NextInode(&cursor, &inode)) {
679  result += StringifyInt(inode) + "\n";
680  }
681  mount_point->inode_tracker()->EndEnumerate(&cursor);
682  talk_mgr->Answer(con_fd, result);
683  } else if (line == "vfs entries") {
684  string result;
686  mount_point->inode_tracker()->BeginEnumerate());
687  uint64_t inode_parent;
688  NameString name;
689  while (mount_point->inode_tracker()->NextEntry(
690  &cursor, &inode_parent, &name))
691  {
692  result += "<" + StringifyInt(inode_parent) + ">/" + name.ToString() +
693  "\n";
694  }
695  mount_point->inode_tracker()->EndEnumerate(&cursor);
696  talk_mgr->Answer(con_fd, result);
697  } else if (line == "version") {
698  string version_str = string(VERSION) + " (CernVM-FS Fuse Module)\n" +
699  cvmfs::loader_exports_->loader_version + " (Loader)\n";
700  talk_mgr->Answer(con_fd, version_str);
701  } else if (line == "version patchlevel") {
702  talk_mgr->Answer(con_fd, string(CVMFS_PATCH_LEVEL) + "\n");
703  } else if (line == "tear down to read-only") {
704  if (file_system->cache_mgr()->id() != kPosixCacheManager) {
705  talk_mgr->Answer(con_fd, "not supported\n");
706  } else {
707  // hack
709  file_system->TearDown2ReadOnly();
710  talk_mgr->Answer(con_fd, "In read-only mode\n");
711  }
712  } else if (line == "latency") {
713  string result = talk_mgr->FormatLatencies(*mount_point, file_system);
714  talk_mgr->Answer(con_fd, result);
715  } else {
716  talk_mgr->Answer(con_fd, "unknown command\n");
717  }
718  }
719 
720  return NULL;
721 } // NOLINT(readability/fn_size)
722 
723 string TalkManager::FormatLatencies(const MountPoint &mount_point,
724  FileSystem *file_system) {
725  string result;
726  const unsigned int bufSize = 300;
727  char buffer[bufSize];
728 
729  vector<float> qs;
730  qs.push_back(.1);
731  qs.push_back(.2);
732  qs.push_back(.25);
733  qs.push_back(.3);
734  qs.push_back(.4);
735  qs.push_back(.5);
736  qs.push_back(.6);
737  qs.push_back(.7);
738  qs.push_back(.75);
739  qs.push_back(.8);
740  qs.push_back(.9);
741  qs.push_back(.95);
742  qs.push_back(.99);
743  qs.push_back(.999);
744  qs.push_back(.9999);
745 
746  string repo(mount_point.fqrn());
747 
748  unsigned int format_index =
749  snprintf(buffer, bufSize, "\"%s\",\"%s\",\"%s\",\"%s\"", "repository",
750  "action", "total_count", "time_unit");
751  for (unsigned int i = 0; i < qs.size(); i++) {
752  format_index += snprintf(buffer + format_index, bufSize - format_index,
753  ",%0.5f", qs[i]);
754  }
755  format_index += snprintf(buffer + format_index, bufSize - format_index, "\n");
756  assert(format_index < bufSize);
757 
758  result += buffer;
759  memset(buffer, 0, sizeof(buffer));
760  format_index = 0;
761 
762  vector<Log2Histogram *> hist;
763  vector<string> names;
764  hist.push_back(file_system->hist_fs_lookup());
765  names.push_back("lookup");
766  hist.push_back(file_system->hist_fs_forget());
767  names.push_back("forget");
768  hist.push_back(file_system->hist_fs_forget_multi());
769  names.push_back("forget_multi");
770  hist.push_back(file_system->hist_fs_getattr());
771  names.push_back("getattr");
772  hist.push_back(file_system->hist_fs_readlink());
773  names.push_back("readlink");
774  hist.push_back(file_system->hist_fs_opendir());
775  names.push_back("opendir");
776  hist.push_back(file_system->hist_fs_releasedir());
777  names.push_back("releasedir");
778  hist.push_back(file_system->hist_fs_readdir());
779  names.push_back("readdir");
780  hist.push_back(file_system->hist_fs_open());
781  names.push_back("open");
782  hist.push_back(file_system->hist_fs_read());
783  names.push_back("read");
784  hist.push_back(file_system->hist_fs_release());
785  names.push_back("release");
786 
787  for (unsigned int j = 0; j < hist.size(); j++) {
788  Log2Histogram *h = hist[j];
789  unsigned int format_index =
790  snprintf(buffer, bufSize, "\"%s\",\"%s\",%" PRIu64 ",\"nanoseconds\"",
791  repo.c_str(), names[j].c_str(), h->N());
792  for (unsigned int i = 0; i < qs.size(); i++) {
793  format_index += snprintf(buffer + format_index, bufSize - format_index,
794  ",%u", h->GetQuantile(qs[i]));
795  }
796  format_index +=
797  snprintf(buffer + format_index, bufSize - format_index, "\n");
798  assert(format_index < bufSize);
799 
800  result += buffer;
801  memset(buffer, 0, sizeof(buffer));
802  format_index = 0;
803  }
804  return result;
805 }
806 
808  const string &socket_path,
809  MountPoint *mount_point,
810  FuseRemounter *remounter)
811  : socket_path_(socket_path)
812  , socket_fd_(-1)
813  , mount_point_(mount_point)
814  , remounter_(remounter)
815  , spawned_(false)
816 {
817  memset(&thread_talk_, 0, sizeof(thread_talk_));
818 }
819 
820 
822  if (!socket_path_.empty()) {
823  int retval = unlink(socket_path_.c_str());
824  if ((retval != 0) && (errno != ENOENT)) {
826  "Could not remove cvmfs_io socket from cache directory (%d)",
827  errno);
828  }
829  }
830 
831  if (socket_fd_ >= 0) {
832  shutdown(socket_fd_, SHUT_RDWR);
833  close(socket_fd_);
834  }
835 
836  if (spawned_) {
837  pthread_join(thread_talk_, NULL);
838  LogCvmfs(kLogTalk, kLogDebug, "talk thread stopped");
839  }
840 }
841 
842 
844  int retval = pthread_create(&thread_talk_, NULL, MainResponder, this);
845  assert(retval == 0);
846  spawned_ = true;
847 }
OptionsManager * options_mgr()
Definition: mountpoint.h:247
NfsMaps * nfs_maps()
Definition: mountpoint.h:235
void UnregisterQuotaListener()
Definition: cvmfs.cc:2105
int MakeSocket(const std::string &path, const int mode)
Definition: posix.cc:331
FileSystem * file_system()
Definition: mountpoint.h:515
Log2Histogram * hist_fs_opendir()
Definition: mountpoint.h:214
Statistics GetStatistics()
Definition: glue_buffer.h:673
EventList history
Definition: loader.h:182
CacheModes cache_mode()
Definition: cache_posix.h:105
virtual uint64_t GetCleanupRate(uint64_t period_s)=0
void SetHostChain(const std::string &host_list)
perf::Statistics * statistics()
Definition: mountpoint.h:534
virtual std::vector< std::string > List()=0
static const int kProbeGeo
Definition: download.h:152
string Trim(const string &raw, bool trim_newline)
Definition: string.cc:428
virtual bool Cleanup(const uint64_t leave_size)=0
string JoinStrings(const vector< string > &strings, const string &joint)
Definition: string.cc:325
std::string PrintInodeGeneration()
Definition: cvmfs.cc:240
Cursor BeginEnumerate()
Definition: glue_buffer.h:763
const history::History * history() const
void SetProxyChain(const std::string &proxy_list, const std::string &fallback_proxy_list, const ProxySetModes set_mode)
Definition: download.cc:2593
std::string fqrn() const
Definition: mountpoint.h:512
MountPoint * mount_point_
Definition: talk.h:57
FuseRemounter * remounter_
Definition: talk.h:58
std::string FormatProxyInfo(download::DownloadManager *download_mgr)
Definition: talk.cc:126
std::string FormatLatencies(const MountPoint &mount_point, FileSystem *file_system)
Definition: talk.cc:723
uint64_t N()
Definition: algorithm.h:164
virtual std::vector< std::string > ListPinned()=0
int socket_fd_
Definition: talk.h:56
Status Check()
Definition: fuse_remount.cc:70
assert((mem||(size==0))&&"Out Of Memory")
MountPoint * mount_point_
Definition: cvmfs.cc:128
bool spawned_
Definition: talk.h:60
Log2Histogram * hist_fs_read()
Definition: mountpoint.h:218
virtual std::vector< std::string > ListCatalogs()=0
std::string loader_version
Definition: loader.h:176
virtual uint64_t GetSize()=0
string StringifyTime(const time_t seconds, const bool utc)
Definition: string.cc:105
void EndEnumerate(Cursor *cursor)
Definition: glue_buffer.h:788
void SetDnsServer(const std::string &address)
Definition: download.cc:1985
virtual CacheManagerIds id()=0
virtual pid_t GetPid()=0
void SetTimeout(const unsigned seconds_proxy, const unsigned seconds_direct)
Definition: download.cc:2043
bool Pin(const string &path)
Definition: cvmfs.cc:1931
unsigned int GetQuantile(float n)
Definition: algorithm.cc:112
static TalkManager * Create(const std::string &socket_path, MountPoint *mount_point, FuseRemounter *remounter)
Definition: talk.cc:78
string * socket_path_
Definition: loader.cc:128
Type type()
Definition: mountpoint.h:249
std::string ToString()
Definition: algorithm.cc:142
string StringifyBool(const bool value)
Definition: string.cc:76
void Answer(int con_fd, const std::string &msg)
Definition: talk.cc:64
pthread_t thread_talk_
Definition: talk.h:59
static uint64_t num_instances()
Definition: shortstring.h:206
pid_t pid_
Definition: cvmfs.cc:153
static pid_t GetPid()
Definition: monitor.cc:172
Counter * Lookup(const std::string &name) const
Definition: statistics.cc:62
glue::PageCacheTracker * page_cache_tracker()
Definition: mountpoint.h:530
void SetMaxTtlMn(unsigned value_minutes)
Definition: mountpoint.cc:1944
void GetProxyInfo(std::vector< std::vector< ProxyInfo > > *proxy_chain, unsigned *current_group, unsigned *fallback_group)
Definition: download.cc:2750
catalog::ClientCatalogManager * catalog_mgr()
Definition: mountpoint.h:501
void Set(const int64_t val)
Definition: statistics.h:33
void TearDown2ReadOnly()
Definition: mountpoint.cc:1132
Log2Histogram * hist_fs_forget_multi()
Definition: mountpoint.h:211
Status CheckSynchronously()
void Flush()
Definition: tracer.cc:106
std::string Dump()
Definition: options.cc:454
Log2Histogram * hist_fs_release()
Definition: mountpoint.h:219
const loader::LoaderExports * loader_exports_
Definition: cvmfs.cc:151
Statistics GetStatistics()
Definition: glue_buffer.h:1019
Statistics GetStatistics()
Definition: glue_buffer.h:850
TalkManager(const std::string &socket_path, MountPoint *mount_point, FuseRemounter *remounter)
Definition: talk.cc:807
virtual std::string GetStatistics()
Definition: nfs_maps.h:37
Log2Histogram * hist_fs_releasedir()
Definition: mountpoint.h:215
const char kSuffixCatalog
Definition: hash.h:54
bool NextEntry(Cursor *cursor, uint64_t *inode_parent, NameString *name)
Definition: glue_buffer.h:769
bool IsNfsSource()
Definition: mountpoint.h:195
CacheManager * cache_mgr()
Definition: mountpoint.h:205
bool NextInode(Cursor *cursor, uint64_t *inode)
Definition: glue_buffer.h:784
bool SendFuseFd(const std::string &socket_path)
Definition: cvmfs.cc:2116
download::DownloadManager * download_mgr()
Definition: mountpoint.h:503
virtual uint64_t GetSizePinned()=0
Status ChangeRoot(const shash::Any &root_hash)
Definition: fuse_remount.cc:30
Log2Histogram * hist_fs_readlink()
Definition: mountpoint.h:213
string StringifyInt(const int64_t value)
Definition: string.cc:78
glue::DentryTracker * dentry_tracker()
Definition: mountpoint.h:529
Log2Histogram * hist_fs_readdir()
Definition: mountpoint.h:216
std::string socket_path_
Definition: talk.h:55
std::string FormatHostInfo(download::DownloadManager *download_mgr)
Definition: talk.cc:99
Log2Histogram * hist_fs_open()
Definition: mountpoint.h:217
std::string GetDnsServer() const
Definition: download.cc:1977
std::string ToString() const
Definition: shortstring.h:141
QuotaManager * quota_mgr()
Definition: cache.h:193
Log2Histogram * hist_fs_lookup()
Definition: mountpoint.h:209
string ResolveProxyDescription(const string &cvmfs_proxies, const std::string &path_fallback_cache, DownloadManager *download_manager)
Definition: wpad.cc:207
uint64_t String2Uint64(const string &value)
Definition: string.cc:228
static void * MainResponder(void *data)
Definition: talk.cc:159
unsigned GetMaxTtlMn()
Definition: mountpoint.cc:1828
void ResetErrorCounters()
Definition: mountpoint.cc:602
bool Evict(const string &path)
Definition: cvmfs.cc:1904
std::string PrintList(const PrintOptions print_options)
Definition: statistics.cc:79
void GetTimeout(unsigned *seconds_proxy, unsigned *seconds_direct)
Definition: download.cc:2066
void GetReloadStatus(bool *drainout_mode, bool *maintenance_mode)
Definition: cvmfs.cc:224
Any MkFromHexPtr(const HexPtr hex, const char suffix)
Definition: hash.cc:83
static const int kProbeUnprobed
Definition: download.h:143
#define MSG_NOSIGNAL
Definition: platform_osx.h:53
Log2Histogram * hist_fs_forget()
Definition: mountpoint.h:210
~TalkManager()
Definition: talk.cc:821
static const int kProbeDown
Definition: download.h:148
static uint64_t num_overflows()
Definition: shortstring.h:207
Log2Histogram * hist_fs_getattr()
Definition: mountpoint.h:212
void GetHostInfo(std::vector< std::string > *host_chain, std::vector< int > *rtt, unsigned *current_host)
Definition: download.cc:2110
std::string PrintHierarchy() const
glue::InodeTracker * inode_tracker()
Definition: mountpoint.h:524
std::string PrintAllMemStatistics() const
static void size_t size
Definition: smalloc.h:54
virtual std::string Describe()=0
Tracer * tracer()
Definition: mountpoint.h:540
void AnswerStringList(int con_fd, const std::vector< std::string > &list)
Definition: talk.cc:69
virtual bool HasCapability(Capabilities capability)=0
download::DownloadManager * external_download_mgr()
Definition: mountpoint.h:504
void String2Uint64Pair(const string &value, uint64_t *a, uint64_t *b)
Definition: string.cc:263
void Spawn()
Definition: talk.cc:843
CVMFS_EXPORT void LogCvmfs(const LogSource source, const int mask, const char *format,...)
Definition: logging.cc:528