GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/publish/repository_transaction.cc
Date: 2025-04-20 02:34:28
Exec Total Coverage
Lines: 0 75 0.0%
Branches: 0 182 0.0%

Line Branch Exec Source
1 /**
2 * This file is part of the CernVM File System.
3 */
4
5
6 #include "publish/repository.h"
7
8 #include <string>
9
10 #include "backoff.h"
11 #include "catalog_mgr_ro.h"
12 #include "catalog_mgr_rw.h"
13 #include "directory_entry.h"
14 #include "manifest.h"
15 #include "publish/except.h"
16 #include "publish/repository_util.h"
17 #include "publish/settings.h"
18 #include "util/exception.h"
19 #include "util/logging.h"
20 #include "util/pointer.h"
21 #include "util/posix.h"
22
23 namespace publish {
24
25
26 void Publisher::TransactionRetry() {
27 bool waiting_on_lease = false;
28 if (managed_node_.IsValid()) {
29 int rvi = managed_node_->Check(false /* is_quiet */);
30 if (rvi != 0) throw EPublish("cannot establish writable mountpoint");
31 }
32
33 BackoffThrottle throttle(500, 5000, 10000);
34 // Negative timeouts (i.e.: no retry) will result in a deadline that has
35 // already passed and thus has the correct effect
36 uint64_t deadline = platform_monotonic_time() +
37 settings_.transaction().GetTimeoutS();
38 if (settings_.transaction().GetTimeoutS() == 0)
39 deadline = uint64_t(-1);
40
41 while (true) {
42 try {
43 TransactionImpl(waiting_on_lease);
44 break;
45 } catch (const publish::EPublish& e) {
46 if (e.failure() != EPublish::kFailTransactionState) {
47 session_->Drop();
48 in_transaction_.Clear();
49 }
50
51 if ((e.failure() == EPublish::kFailTransactionState) ||
52 (e.failure() == EPublish::kFailLeaseBusy))
53 {
54 if (platform_monotonic_time() > deadline)
55 throw;
56
57 waiting_on_lease = true;
58 LogCvmfs(kLogCvmfs, kLogStdout, "repository busy, retrying");
59 throttle.Throttle();
60 continue;
61 }
62
63 throw;
64 } // try-catch
65 } // while (true)
66
67 if (managed_node_.IsValid())
68 managed_node_->Open();
69 }
70
71
72 void Publisher::TransactionImpl(bool waiting_on_lease) {
73 if (in_transaction_.IsSet()) {
74 throw EPublish("another transaction is already open",
75 EPublish::kFailTransactionState);
76 }
77
78 InitSpoolArea();
79
80 // On error, Transaction() will release the transaction lock and drop
81 // the session
82 session_->Acquire();
83
84 // We might have a valid lease for a non-existing path. Nevertheless, we run
85 // run into problems when merging catalogs later, so for the time being we
86 // disallow transactions on non-existing paths.
87 if (!settings_.transaction().lease_path().empty()) {
88 std::string path = GetParentPath(
89 "/" + settings_.transaction().lease_path());
90 catalog::SimpleCatalogManager *catalog_mgr = GetSimpleCatalogManager();
91 catalog::DirectoryEntry dirent;
92 bool retval = catalog_mgr->LookupPath(path, catalog::kLookupDefault,
93 &dirent);
94 if (!retval) {
95 throw EPublish("cannot open transaction on non-existing path " + path,
96 EPublish::kFailLeaseNoEntry);
97 }
98 if (!dirent.IsDirectory()) {
99 throw EPublish(
100 "cannot open transaction on " + path + ", which is not a directory",
101 EPublish::kFailLeaseNoDir);
102 }
103 }
104
105
106 UniquePtr<CheckoutMarker> marker(CheckoutMarker::CreateFrom(
107 settings_.transaction().spool_area().checkout_marker()));
108 // TODO(jblomer): take root hash from r/o mountpoint?
109
110
111 if (settings_.storage().type() == upload::SpoolerDefinition::Gateway && waiting_on_lease) {
112 DownloadRootObjects(settings_.url(), settings_.fqrn(), settings_.transaction().spool_area().tmp_dir());
113 int rvi = managed_node_->Check(true /* is_quiet */);
114 if (rvi != 0) throw EPublish("cannot establish writable mountpoint");
115 }
116
117 in_transaction_.Set();
118 ConstructSpoolers();
119 if (marker.IsValid())
120 settings_.GetTransaction()->SetBaseHash(marker->hash());
121 else
122 settings_.GetTransaction()->SetBaseHash(manifest_->catalog_hash());
123
124 if (settings_.transaction().HasTemplate()) {
125 LogCvmfs(kLogCvmfs, llvl_ | kLogStdout | kLogNoLinebreak,
126 "CernVM-FS: cloning template %s --> %s ... ",
127 settings_.transaction().template_from().c_str(),
128 settings_.transaction().template_to().c_str());
129 ConstructSyncManagers();
130
131 try {
132 catalog_mgr_->CloneTree(settings_.transaction().template_from(),
133 settings_.transaction().template_to());
134 } catch (const ECvmfsException &e) {
135 std::string panic_msg = e.what();
136 in_transaction_.Clear();
137 // TODO(aandvalenzuela): release session token (gateway publishing)
138 throw publish::EPublish("cannot clone directory tree. " + panic_msg,
139 publish::EPublish::kFailInput);
140 }
141
142 Sync();
143 SendTalkCommand(settings_.transaction().spool_area().readonly_talk_socket(),
144 "chroot " + settings_.transaction().base_hash().ToString() + "\n");
145 LogCvmfs(kLogCvmfs, llvl_ | kLogStdout, "[done]");
146 // TODO(jblomer): fix-me
147 // PushReflog();
148 }
149
150 LogCvmfs(kLogCvmfs, llvl_ | kLogDebug | kLogSyslog,
151 "(%s) opened transaction", settings_.fqrn().c_str());
152 }
153
154 } // namespace publish
155