1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2019-2019 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23
24 #include "include/bareos.h"
25 #include "include/jcr.h"
26 #include "lib/recent_job_results_list.h"
27 #include "lib/dlist.h"
28 #include "lib/berrno.h"
29
30 #include <vector>
31 #include <mutex>
32 #include <fstream>
33
34 static std::vector<RecentJobResultsList::JobResult> recent_job_results_list;
35 static const int max_count_recent_job_results = 10;
36 static std::mutex mutex;
37
Cleanup()38 void RecentJobResultsList::Cleanup()
39 {
40 std::lock_guard<std::mutex> lg(mutex);
41 if (!recent_job_results_list.empty()) { recent_job_results_list.clear(); }
42 }
43
ImportFromFile(std::ifstream & file)44 bool RecentJobResultsList::ImportFromFile(std::ifstream& file)
45 {
46 #if defined HAVE_IS_TRIVIALLY_COPYABLE
47 static_assert(
48 std::is_trivially_copyable<RecentJobResultsList::JobResult>::value,
49 "RecentJobResultsList::JobResult must be trivially copyable");
50 #endif
51
52 uint32_t num;
53
54 try {
55 file.read(reinterpret_cast<char*>(&num), sizeof(num));
56
57 Dmsg1(100, "Read num_items=%d\n", num);
58 if (num > 4 * max_count_recent_job_results) { /* sanity check */
59 return false;
60 }
61
62 std::lock_guard<std::mutex> m(mutex);
63
64 for (; num; num--) {
65 RecentJobResultsList::JobResult job;
66 file.read(reinterpret_cast<char*>(&job), sizeof(job));
67 if (job.JobId > 0) {
68 recent_job_results_list.push_back(job);
69 if (recent_job_results_list.size() > max_count_recent_job_results) {
70 recent_job_results_list.erase(recent_job_results_list.begin());
71 }
72 }
73 }
74 } catch (const std::system_error& e) {
75 BErrNo be;
76 Dmsg3(010, "Could not open or read state file. ERR=%s - %s\n",
77 be.bstrerror(), e.code().message().c_str());
78 return false;
79 } catch (const std::exception& e) {
80 Dmsg0(100, "Could not open or read file. Some error occurred: %s\n",
81 e.what());
82 return false;
83 }
84 return true;
85 }
86
ExportToFile(std::ofstream & file)87 bool RecentJobResultsList::ExportToFile(std::ofstream& file)
88 {
89 if (!recent_job_results_list.empty()) {
90 std::lock_guard<std::mutex> m(mutex);
91 uint32_t num
92 = recent_job_results_list.size(); // always first entry in the file
93
94 #if defined HAVE_IS_TRIVIALLY_COPYABLE
95 static_assert(
96 std::is_trivially_copyable<RecentJobResultsList::JobResult>::value,
97 "RecentJobResultsList::JobResult must be trivially copyable");
98 #endif
99
100 try {
101 file.write(reinterpret_cast<char*>(&num), sizeof(num));
102
103 for (const auto& je : recent_job_results_list) {
104 file.write(reinterpret_cast<const char*>(&je),
105 sizeof(struct RecentJobResultsList::JobResult));
106 }
107 } catch (const std::system_error& e) {
108 BErrNo be;
109 Dmsg3(010, "Could not write state file. ERR=%s - %s\n", be.bstrerror(),
110 e.code().message().c_str());
111 return false;
112 } catch (const std::exception& e) {
113 Dmsg0(100, "Could not write file. Some error occurred: %s\n", e.what());
114 return false;
115 }
116 }
117 return true;
118 }
119
Append(JobControlRecord * jcr)120 void RecentJobResultsList::Append(JobControlRecord* jcr)
121 {
122 RecentJobResultsList::JobResult je;
123 je.Errors = jcr->JobErrors;
124 je.JobType = jcr->getJobType();
125 je.JobId = jcr->JobId;
126 je.VolSessionId = jcr->VolSessionId;
127 je.VolSessionTime = jcr->VolSessionTime;
128 bstrncpy(je.Job, jcr->Job, sizeof(je.Job));
129 je.JobFiles = jcr->JobFiles;
130 je.JobBytes = jcr->JobBytes;
131 je.JobStatus = jcr->JobStatus;
132 je.JobLevel = jcr->getJobLevel();
133 je.start_time = jcr->start_time;
134 je.end_time = time(nullptr);
135
136 std::lock_guard<std::mutex> lg(mutex);
137 recent_job_results_list.push_back(je);
138 if (recent_job_results_list.size() > max_count_recent_job_results) {
139 recent_job_results_list.erase(recent_job_results_list.begin());
140 }
141 }
142
Get()143 std::vector<RecentJobResultsList::JobResult> RecentJobResultsList::Get()
144 {
145 std::lock_guard<std::mutex> lg(mutex);
146 return recent_job_results_list;
147 }
148
Count()149 std::size_t RecentJobResultsList::Count()
150 {
151 std::lock_guard<std::mutex> lg(mutex);
152 return recent_job_results_list.size();
153 }
154
IsEmpty()155 bool RecentJobResultsList::IsEmpty()
156 {
157 std::lock_guard<std::mutex> lg(mutex);
158 return recent_job_results_list.empty();
159 }
160
161
GetMostRecentJobResult()162 RecentJobResultsList::JobResult RecentJobResultsList::GetMostRecentJobResult()
163 {
164 std::lock_guard<std::mutex> lg(mutex);
165 if (recent_job_results_list.size()) {
166 return recent_job_results_list.front();
167 }
168 return RecentJobResultsList::JobResult{};
169 }
170