Directory: | cvmfs/ |
---|---|
File: | cvmfs/history.h |
Date: | 2025-02-09 02:34:19 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 21 | 21 | 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 | 173 | Branch() : initial_revision(0) { } | |
37 | 239 | Branch(const std::string &b, const std::string &p, uint64_t r) | |
38 |
1/2✓ Branch 2 taken 239 times.
✗ Branch 3 not taken.
|
239 | : branch(b), parent(p), initial_revision(r) { } |
39 | std::string branch; | ||
40 | std::string parent; | ||
41 | uint64_t initial_revision; | ||
42 | |||
43 | 22 | bool operator ==(const Branch &other) const { | |
44 |
1/2✓ Branch 1 taken 22 times.
✗ Branch 2 not taken.
|
44 | return (this->branch == other.branch) && |
45 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
44 | (this->parent == other.parent) && |
46 |
1/2✓ Branch 0 taken 22 times.
✗ Branch 1 not taken.
|
44 | (this->initial_revision == other.initial_revision); |
47 | } | ||
48 | |||
49 | // Used for sorting in unit tests | ||
50 | 44 | bool operator <(const Branch &other) const { | |
51 | 44 | return (this->branch < other.branch); | |
52 | } | ||
53 | }; | ||
54 | |||
55 | /** | ||
56 | * The Tag structure contains information about one specific named snap- | ||
57 | * shot stored in the history database. Tags can be retrieved from this | ||
58 | * history class both by 'name' and by 'date'. By 'date' branches only look | ||
59 | * in the default branch. Naturally, tags can also be saved into the History | ||
60 | * using this struct as a container. | ||
61 | */ | ||
62 | struct Tag { | ||
63 |
1/2✓ Branch 2 taken 17652 times.
✗ Branch 3 not taken.
|
17652 | Tag() : size(0), revision(0), timestamp(0) {} |
64 | |||
65 | 294 | Tag(const std::string &n, const shash::Any &h, const uint64_t s, | |
66 | const uint64_t r, const time_t t, const std::string &d, | ||
67 | 294 | const std::string &b) : | |
68 | 294 | name(n), root_hash(h), size(s), revision(r), timestamp(t), | |
69 |
2/4✓ Branch 1 taken 294 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 294 times.
✗ Branch 5 not taken.
|
294 | description(d), branch(b) {} |
70 | |||
71 | bool operator ==(const Tag &other) const { | ||
72 | return (this->branch == other.branch) && | ||
73 | (this->revision == other.revision); | ||
74 | } | ||
75 | |||
76 | 35117 | bool operator <(const Tag &other) const { | |
77 |
2/2✓ Branch 0 taken 34931 times.
✓ Branch 1 taken 186 times.
|
35117 | if (this->timestamp == other.timestamp) |
78 | 34931 | return this->revision < other.revision; | |
79 | 186 | return this->timestamp < other.timestamp; | |
80 | } | ||
81 | |||
82 | bool operator >(const Tag &other) const { | ||
83 | if (this->timestamp == other.timestamp) | ||
84 | return this->revision > other.revision; | ||
85 | return this->timestamp > other.timestamp; | ||
86 | } | ||
87 | |||
88 | std::string name; | ||
89 | shash::Any root_hash; | ||
90 | uint64_t size; | ||
91 | uint64_t revision; | ||
92 | time_t timestamp; | ||
93 | std::string description; | ||
94 | /** | ||
95 | * The default branch is the empty string. | ||
96 | */ | ||
97 | std::string branch; | ||
98 | }; // struct Tag | ||
99 | |||
100 | |||
101 | public: | ||
102 | 632 | virtual ~History() { } | |
103 | |||
104 | virtual bool IsWritable() const = 0; | ||
105 | virtual unsigned GetNumberOfTags() const = 0; | ||
106 | |||
107 | /** | ||
108 | * Opens a new database transaction in the underlying SQLite database | ||
109 | * This can greatly improve performance when used before inserting or | ||
110 | * removing multiple tags. | ||
111 | */ | ||
112 | virtual bool BeginTransaction() const = 0; | ||
113 | |||
114 | /** | ||
115 | * Closes a transaction (see BeginTransaction()) | ||
116 | */ | ||
117 | virtual bool CommitTransaction() const = 0; | ||
118 | |||
119 | /** | ||
120 | * Sets the internal pointer to the previous revision of this History file. | ||
121 | * Note: This must be handled by the user code. | ||
122 | * | ||
123 | * @param history_hash the content hash of the previous revision | ||
124 | */ | ||
125 | virtual bool SetPreviousRevision(const shash::Any &history_hash) = 0; | ||
126 | virtual shash::Any previous_revision() const = 0; | ||
127 | |||
128 | virtual bool Insert(const Tag &tag) = 0; | ||
129 | virtual bool Remove(const std::string &name) = 0; | ||
130 | virtual bool Exists(const std::string &name) const = 0; | ||
131 | virtual bool GetByName(const std::string &name, Tag *tag) const = 0; | ||
132 | virtual bool GetByDate(const time_t timestamp, Tag *tag) const = 0; | ||
133 | virtual bool List(std::vector<Tag> *tags) const = 0; | ||
134 | |||
135 | virtual bool GetBranchHead(const std::string &branch_name, Tag *tag) | ||
136 | const = 0; | ||
137 | virtual bool ExistsBranch(const std::string &branch_name) const = 0; | ||
138 | virtual bool InsertBranch(const Branch &branch) = 0; | ||
139 | /** | ||
140 | * When removing tags, branches can become abandoned. Remove abandoned | ||
141 | * branches and redirect the parent pointer of their child branches. | ||
142 | */ | ||
143 | virtual bool PruneBranches() = 0; | ||
144 | virtual bool ListBranches(std::vector<Branch> *branches) const = 0; | ||
145 | |||
146 | /** | ||
147 | * The recycle bin operations are deprecated, only emptying and listing are | ||
148 | * preserved for migration and testing. | ||
149 | */ | ||
150 | virtual bool ListRecycleBin(std::vector<shash::Any> *hashes) const = 0; | ||
151 | virtual bool EmptyRecycleBin() = 0; | ||
152 | |||
153 | /** | ||
154 | * Rolls back the history to the provided target tag and deletes all tags | ||
155 | * in between. Works on the default branch only. | ||
156 | * | ||
157 | * Note: this assumes that the provided target tag was already updated with | ||
158 | * the republished root catalog information. | ||
159 | * | ||
160 | * @param updated_target_tag the tag to be rolled back to (updated: see Note) | ||
161 | * @return true on success | ||
162 | */ | ||
163 | virtual bool Rollback(const Tag &updated_target_tag) = 0; | ||
164 | |||
165 | /** | ||
166 | * Lists the tags that would be deleted by a rollback to the tag specified. | ||
167 | * | ||
168 | * Note: This doesn't change the database but is mainly used for sanity checks | ||
169 | * and user output. | ||
170 | * | ||
171 | * @param target_tag_name the tag name for the planned rollback | ||
172 | * @param tags pointer to the result tag list to be filled | ||
173 | * @return true on success | ||
174 | */ | ||
175 | virtual bool ListTagsAffectedByRollback(const std::string &target_tag_name, | ||
176 | std::vector<Tag> *tags) const = 0; | ||
177 | |||
178 | /** | ||
179 | * Provides a list of all referenced catalog hashes in this History. | ||
180 | * The hashes will be ordered by their timestamp in ascending order. | ||
181 | * | ||
182 | * @param hashes pointer to the result vector to be filled | ||
183 | */ | ||
184 | virtual bool GetHashes(std::vector<shash::Any> *hashes) const = 0; | ||
185 | |||
186 | // database file management controls | ||
187 | virtual void TakeDatabaseFileOwnership() = 0; | ||
188 | virtual void DropDatabaseFileOwnership() = 0; | ||
189 | virtual bool OwnsDatabaseFile() const = 0; | ||
190 | |||
191 | virtual bool Vacuum() = 0; | ||
192 | |||
193 | 228 | const std::string& fqrn() const { return fqrn_; } | |
194 | |||
195 | protected: | ||
196 | 316 | void set_fqrn(const std::string &fqrn) { fqrn_ = fqrn; } | |
197 | |||
198 | private: | ||
199 | std::string fqrn_; | ||
200 | }; | ||
201 | |||
202 | } // namespace history | ||
203 | |||
204 | #endif // CVMFS_HISTORY_H_ | ||
205 |