Directory: | cvmfs/ |
---|---|
File: | cvmfs/history.h |
Date: | 2025-07-13 02:35:07 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 24 | 24 | 100.0% |
Branches: | 9 | 16 | 56.2% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | */ | ||
4 | |||
5 | #ifndef CVMFS_HISTORY_H_ | ||
6 | #define CVMFS_HISTORY_H_ | ||
7 | |||
8 | #include <stdint.h> | ||
9 | #include <time.h> | ||
10 | |||
11 | #include <string> | ||
12 | #include <vector> | ||
13 | |||
14 | #include "crypto/hash.h" | ||
15 | |||
16 | namespace history { | ||
17 | |||
18 | /** | ||
19 | * This is the abstract base class for repository history. It maintains a list | ||
20 | * of named snapshots in a Tag structure. | ||
21 | * | ||
22 | * Each tag contains meta information (i.e. description, date) and points to | ||
23 | * one specific catalog revision (revision, root catalog hash). Furthermore | ||
24 | * tags are associated with _one_ branch. This can be used in clients | ||
25 | * to selectively apply file system snapshots of a specific branch. | ||
26 | * | ||
27 | * Note: The public interface of the History class is virtual, in order to over- | ||
28 | * write it in a testing environment. As we are dealing with an SQLite | ||
29 | * database anyway, the overhead of this should not matter. | ||
30 | * It could be implemented using CRTP if necessary, but would require com- | ||
31 | * plex code to do so. | ||
32 | */ | ||
33 | class History { | ||
34 | public: | ||
35 | struct Branch { | ||
36 | 6028 | Branch() : initial_revision(0) { } | |
37 | 7106 | Branch(const std::string &b, const std::string &p, uint64_t r) | |
38 |
1/2✓ Branch 2 taken 7106 times.
✗ Branch 3 not taken.
|
7106 | : branch(b), parent(p), initial_revision(r) { } |
39 | std::string branch; | ||
40 | std::string parent; | ||
41 | uint64_t initial_revision; | ||
42 | |||
43 | 486 | bool operator==(const Branch &other) const { | |
44 |
1/2✓ Branch 2 taken 486 times.
✗ Branch 3 not taken.
|
972 | return (this->branch == other.branch) && (this->parent == other.parent) |
45 |
2/4✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 486 times.
✗ Branch 3 not taken.
|
972 | && (this->initial_revision == other.initial_revision); |
46 | } | ||
47 | |||
48 | // Used for sorting in unit tests | ||
49 | 1162 | bool operator<(const Branch &other) const { | |
50 | 1162 | return (this->branch < other.branch); | |
51 | } | ||
52 | }; | ||
53 | |||
54 | /** | ||
55 | * The Tag structure contains information about one specific named snap- | ||
56 | * shot stored in the history database. Tags can be retrieved from this | ||
57 | * history class both by 'name' and by 'date'. By 'date' branches only look | ||
58 | * in the default branch. Naturally, tags can also be saved into the History | ||
59 | * using this struct as a container. | ||
60 | */ | ||
61 | struct Tag { | ||
62 |
1/2✓ Branch 2 taken 632984 times.
✗ Branch 3 not taken.
|
632984 | Tag() : size(0), revision(0), timestamp(0) { } |
63 | |||
64 | 11298 | Tag(const std::string &n, const shash::Any &h, const uint64_t s, | |
65 | const uint64_t r, const time_t t, const std::string &d, | ||
66 | const std::string &b) | ||
67 | 11298 | : name(n) | |
68 | 11298 | , root_hash(h) | |
69 | 11298 | , size(s) | |
70 | 11298 | , revision(r) | |
71 | 11298 | , timestamp(t) | |
72 |
1/2✓ Branch 1 taken 11298 times.
✗ Branch 2 not taken.
|
11298 | , description(d) |
73 |
1/2✓ Branch 1 taken 11298 times.
✗ Branch 2 not taken.
|
11298 | , branch(b) { } |
74 | |||
75 | bool operator==(const Tag &other) const { | ||
76 | return (this->branch == other.branch) | ||
77 | && (this->revision == other.revision); | ||
78 | } | ||
79 | |||
80 | 1683395 | bool operator<(const Tag &other) const { | |
81 |
2/2✓ Branch 0 taken 1676688 times.
✓ Branch 1 taken 6707 times.
|
1683395 | if (this->timestamp == other.timestamp) |
82 | 1676688 | return this->revision < other.revision; | |
83 | 6707 | return this->timestamp < other.timestamp; | |
84 | } | ||
85 | |||
86 | bool operator>(const Tag &other) const { | ||
87 | if (this->timestamp == other.timestamp) | ||
88 | return this->revision > other.revision; | ||
89 | return this->timestamp > other.timestamp; | ||
90 | } | ||
91 | |||
92 | std::string name; | ||
93 | shash::Any root_hash; | ||
94 | uint64_t size; | ||
95 | uint64_t revision; | ||
96 | time_t timestamp; | ||
97 | std::string description; | ||
98 | /** | ||
99 | * The default branch is the empty string. | ||
100 | */ | ||
101 | std::string branch; | ||
102 | }; // struct Tag | ||
103 | |||
104 | |||
105 | public: | ||
106 | 16862 | virtual ~History() { } | |
107 | |||
108 | virtual bool IsWritable() const = 0; | ||
109 | virtual unsigned GetNumberOfTags() const = 0; | ||
110 | |||
111 | /** | ||
112 | * Opens a new database transaction in the underlying SQLite database | ||
113 | * This can greatly improve performance when used before inserting or | ||
114 | * removing multiple tags. | ||
115 | */ | ||
116 | virtual bool BeginTransaction() const = 0; | ||
117 | |||
118 | /** | ||
119 | * Closes a transaction (see BeginTransaction()) | ||
120 | */ | ||
121 | virtual bool CommitTransaction() const = 0; | ||
122 | |||
123 | /** | ||
124 | * Sets the internal pointer to the previous revision of this History file. | ||
125 | * Note: This must be handled by the user code. | ||
126 | * | ||
127 | * @param history_hash the content hash of the previous revision | ||
128 | */ | ||
129 | virtual bool SetPreviousRevision(const shash::Any &history_hash) = 0; | ||
130 | virtual shash::Any previous_revision() const = 0; | ||
131 | |||
132 | virtual bool Insert(const Tag &tag) = 0; | ||
133 | virtual bool Remove(const std::string &name) = 0; | ||
134 | virtual bool Exists(const std::string &name) const = 0; | ||
135 | virtual bool GetByName(const std::string &name, Tag *tag) const = 0; | ||
136 | virtual bool GetByDate(const time_t timestamp, Tag *tag) const = 0; | ||
137 | virtual bool List(std::vector<Tag> *tags) const = 0; | ||
138 | |||
139 | virtual bool GetBranchHead(const std::string &branch_name, | ||
140 | Tag *tag) const = 0; | ||
141 | virtual bool ExistsBranch(const std::string &branch_name) const = 0; | ||
142 | virtual bool InsertBranch(const Branch &branch) = 0; | ||
143 | /** | ||
144 | * When removing tags, branches can become abandoned. Remove abandoned | ||
145 | * branches and redirect the parent pointer of their child branches. | ||
146 | */ | ||
147 | virtual bool PruneBranches() = 0; | ||
148 | virtual bool ListBranches(std::vector<Branch> *branches) const = 0; | ||
149 | |||
150 | /** | ||
151 | * The recycle bin operations are deprecated, only emptying and listing are | ||
152 | * preserved for migration and testing. | ||
153 | */ | ||
154 | virtual bool ListRecycleBin(std::vector<shash::Any> *hashes) const = 0; | ||
155 | virtual bool EmptyRecycleBin() = 0; | ||
156 | |||
157 | /** | ||
158 | * Rolls back the history to the provided target tag and deletes all tags | ||
159 | * in between. Works on the default branch only. | ||
160 | * | ||
161 | * Note: this assumes that the provided target tag was already updated with | ||
162 | * the republished root catalog information. | ||
163 | * | ||
164 | * @param updated_target_tag the tag to be rolled back to (updated: see Note) | ||
165 | * @return true on success | ||
166 | */ | ||
167 | virtual bool Rollback(const Tag &updated_target_tag) = 0; | ||
168 | |||
169 | /** | ||
170 | * Lists the tags that would be deleted by a rollback to the tag specified. | ||
171 | * | ||
172 | * Note: This doesn't change the database but is mainly used for sanity checks | ||
173 | * and user output. | ||
174 | * | ||
175 | * @param target_tag_name the tag name for the planned rollback | ||
176 | * @param tags pointer to the result tag list to be filled | ||
177 | * @return true on success | ||
178 | */ | ||
179 | virtual bool ListTagsAffectedByRollback(const std::string &target_tag_name, | ||
180 | std::vector<Tag> *tags) const = 0; | ||
181 | |||
182 | /** | ||
183 | * Provides a list of all referenced catalog hashes in this History. | ||
184 | * The hashes will be ordered by their timestamp in ascending order. | ||
185 | * | ||
186 | * @param hashes pointer to the result vector to be filled | ||
187 | */ | ||
188 | virtual bool GetHashes(std::vector<shash::Any> *hashes) const = 0; | ||
189 | |||
190 | // database file management controls | ||
191 | virtual void TakeDatabaseFileOwnership() = 0; | ||
192 | virtual void DropDatabaseFileOwnership() = 0; | ||
193 | virtual bool OwnsDatabaseFile() const = 0; | ||
194 | |||
195 | virtual bool Vacuum() = 0; | ||
196 | |||
197 | 4939 | const std::string &fqrn() const { return fqrn_; } | |
198 | |||
199 | protected: | ||
200 | 8431 | void set_fqrn(const std::string &fqrn) { fqrn_ = fqrn; } | |
201 | |||
202 | private: | ||
203 | std::string fqrn_; | ||
204 | }; | ||
205 | |||
206 | } // namespace history | ||
207 | |||
208 | #endif // CVMFS_HISTORY_H_ | ||
209 |