1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include <boost/filesystem/path.hpp>
34 #include <memory>
35 #include <tuple>
36 #include <vector>
37 
38 #include "mongo/base/disallow_copying.h"
39 #include "mongo/base/status.h"
40 #include "mongo/base/string_data.h"
41 #include "mongo/db/ftdc/collector.h"
42 #include "mongo/db/ftdc/config.h"
43 #include "mongo/db/ftdc/file_writer.h"
44 #include "mongo/db/ftdc/util.h"
45 #include "mongo/db/jsobj.h"
46 
47 namespace mongo {
48 
49 class Client;
50 
51 /**
52  * Manages a directory full of archive files, and an interim file.
53  *
54  * Manages file rotation, and directory size management.
55  */
56 class FTDCFileManager {
57     MONGO_DISALLOW_COPYING(FTDCFileManager);
58 
59 public:
60     ~FTDCFileManager();
61 
62     /**
63      * Creates the directory if it does not exist.
64      * NOTE: This must be run on a thread with a Client context, i.e., not a static initializer.
65      *
66      * Collectors are used to collect data to be stored as metadata on file rotation or system
67      * restart.
68      *
69      * Recovers data from the interim file as needed.
70      * Rotates files if needed.
71      */
72     static StatusWith<std::unique_ptr<FTDCFileManager>> create(const FTDCConfig* config,
73                                                                const boost::filesystem::path& path,
74                                                                FTDCCollectorCollection* collection,
75                                                                Client* client);
76 
77     /**
78      * Rotates files
79      */
80     Status rotate(Client* client);
81 
82     /**
83      * Writes a sample to disk via FTDCFileWriter.
84      *
85      * Rotates files as needed.
86      */
87     Status writeSampleAndRotateIfNeeded(Client* client, const BSONObj& sample, Date_t date);
88 
89     /**
90      * Closes the current file manager down.
91      */
92     Status close();
93 
94 public:
95     /**
96      * Generate a new file name for the archive.
97      * Public for use by unit tests only.
98      */
99     StatusWith<boost::filesystem::path> generateArchiveFileName(const boost::filesystem::path& path,
100                                                                 StringData suffix);
101 
102 private:
103     FTDCFileManager(const FTDCConfig* config,
104                     const boost::filesystem::path& path,
105                     FTDCCollectorCollection* collection);
106 
107     /**
108      * Gets a list of metrics files in a directory.
109      */
110     std::vector<boost::filesystem::path> scanDirectory();
111 
112     /**
113      * Recover the interim file.
114      *
115      * Checks if the file is non-empty, and if gets a list of documents with the original times they
116      * were written disk based on the _id fields.
117      */
118     std::vector<std::tuple<FTDCBSONUtil::FTDCType, BSONObj, Date_t>> recoverInterimFile();
119 
120     /**
121      * Removes the oldest files if the directory is over quota
122      */
123     Status trimDirectory(std::vector<boost::filesystem::path>& files);
124 
125     /**
126      * Open a new file for writing.
127      *
128      * Steps:
129      * 1. Writes any recovered interim file samples into the file. These entries are written to the
130      *    archive file with the time they were written to the interim file instead of the time this
131      *    recovery is written.
132      * 2. Appends file rotation collectors upon opening the file.
133      */
134     Status openArchiveFile(
135         Client* client,
136         const boost::filesystem::path& path,
137         const std::vector<std::tuple<FTDCBSONUtil::FTDCType, BSONObj, Date_t>>& docs);
138 
139 private:
140     // config to use
141     const FTDCConfig* const _config;
142 
143     // file to log samples to
144     FTDCFileWriter _writer;
145 
146     // last archive file name suffix used
147     std::string _previousArchiveFileSuffix;
148 
149     // last file name id uniquifier used
150     // this starts from zero for each new file suffix
151     std::uint32_t _fileNameUniquifier = 0;
152 
153     // Path of metrics directory
154     boost::filesystem::path _path;
155 
156     // collection of collectors to add to new files on rotation, and server restart
157     FTDCCollectorCollection* const _rotateCollectors;
158 };
159 
160 }  // namespace mongo
161