Skip to content

Commit

Permalink
feat: Add some useful time and filesystem utilies (#2020)
Browse files Browse the repository at this point in the history
  • Loading branch information
acelyc111 authored May 23, 2024
1 parent caf5c50 commit b0033c8
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 8 deletions.
39 changes: 39 additions & 0 deletions src/utils/filesystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@
*/

#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/system/error_code.hpp>
#include <errno.h>
#include <fmt/core.h>
#include <ftw.h>
#include <glob.h>
#include <limits.h>
#include <openssl/md5.h>
#include <rocksdb/env.h>
Expand All @@ -42,6 +44,7 @@
#include <memory>

#include "absl/strings/string_view.h"
#include "errors.h"
#include "utils/defer.h"
#include "utils/env.h"
#include "utils/fail_point.h"
Expand Down Expand Up @@ -492,6 +495,12 @@ bool create_file(const std::string &path)
return true;
}

bool is_absolute_path(const std::string &path)
{
boost::filesystem::path p(path);
return p.is_absolute();
}

bool get_absolute_path(const std::string &path1, std::string &path2)
{
bool succ;
Expand Down Expand Up @@ -901,6 +910,36 @@ bool check_dir_rw(const std::string &path, std::string &err_msg)
return true;
}

error_s glob(const std::string &path_pattern, std::vector<std::string> &path_list)
{
glob_t result;
auto cleanup = dsn::defer([&] { ::globfree(&result); });

errno = 0;
int ret = ::glob(path_pattern.c_str(), GLOB_TILDE | GLOB_ERR, NULL, &result);
switch (ret) {
case 0:
break;

case GLOB_NOMATCH:
return error_s::ok();

case GLOB_NOSPACE:
return error_s::make(ERR_FS_INTERNAL, "glob out of memory");

default:
std::string error(errno == 0 ? "unknown error" : safe_strerror(errno));
return error_s::make(ERR_FS_INTERNAL,
fmt::format("glob failed for '{}': {}", path_pattern, error));
}

for (size_t i = 0; i < result.gl_pathc; ++i) {
path_list.emplace_back(result.gl_pathv[i]);
}

return error_s::ok();
}

} // namespace filesystem
} // namespace utils
} // namespace dsn
10 changes: 10 additions & 0 deletions src/utils/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include <utility>
#include <vector>

#include "utils/errors.h"
#include "utils/error_code.h"

#ifndef _XOPEN_SOURCE
Expand Down Expand Up @@ -69,6 +70,8 @@ namespace filesystem {

void get_normalized_path(const std::string &path, std::string &npath);

bool is_absolute_path(const std::string &path);

bool get_absolute_path(const std::string &path1, std::string &path2);

std::string remove_file_name(const std::string &path);
Expand Down Expand Up @@ -165,6 +168,13 @@ bool create_directory(const std::string &path,
// call `create_directory` before to make `path` exist
bool check_dir_rw(const std::string &path, /*out*/ std::string &err_msg);

// Finds paths on the filesystem matching a pattern.
//
// The found pathnames are added to the 'paths' vector. If no pathnames are
// found matching the pattern, no paths are added to the vector and an OK
// status is returned.
error_s glob(const std::string &path_pattern, std::vector<std::string> &path_list);

} // namespace filesystem
} // namespace utils
} // namespace dsn
34 changes: 34 additions & 0 deletions src/utils/test/file_system_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,12 @@
#include <rocksdb/env.h>
#include <rocksdb/slice.h>
#include <rocksdb/status.h>
#include <stddef.h>
#include <stdint.h>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "gtest/gtest.h"
#include "utils/env.h"
Expand Down Expand Up @@ -175,6 +178,37 @@ TEST(filesystem_test, verify_file_test)
remove_path(fname);
}

TEST(filesystem_test, absolute_path_test)
{
const std::string kTestDir = "absolute_path_test";
ASSERT_TRUE(create_directory(kTestDir));
ASSERT_FALSE(is_absolute_path(kTestDir));

std::string abs_path;
ASSERT_TRUE(get_absolute_path(kTestDir, abs_path));
ASSERT_TRUE(is_absolute_path(abs_path));
}

TEST(filesystem_test, glob_test)
{
const std::string kTestDir = "glob_test";
ASSERT_TRUE(create_directory(kTestDir));
std::vector<std::string> filenames = {"fuzz", "fuzzy", "fuzzyiest", "buzz"};
std::vector<std::pair<std::string, size_t>> matchers = {
{"file", 0}, {"fuzz", 1}, {"fuzz*", 3}, {"?uzz", 2},
};

for (const auto &name : filenames) {
ASSERT_TRUE(create_file(path_combine(kTestDir, name)));
}

for (const auto & [ path_pattern, matched_count ] : matchers) {
std::vector<std::string> matches;
ASSERT_TRUE(glob(path_combine(kTestDir, path_pattern), matches)) << path_pattern;
ASSERT_EQ(matched_count, matches.size()) << path_pattern;
}
}

} // namespace filesystem
} // namespace utils
} // namespace dsn
25 changes: 20 additions & 5 deletions src/utils/test/time_utils_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,16 @@ TEST(time_utils, get_current_physical_time_ns)
template <typename T>
void test_time_ms_to_string(T &str)
{
time_ms_to_string(1605091506136, str);
time_ms_to_string(1605091506036, str);

std::string actual_str(str);

// Time differ between time zones.
// Time differs between time zones.
//
// The real time 2020-11-11 18:45:06.136 (UTC+8)
// so it must be 2020-11-1x xx:45:06.136.
// The real time 2020-11-11 18:45:06.036 (UTC+8)
// so it must be 2020-11-1x xx:45:06.036.
ASSERT_EQ(std::string("2020-11-1"), actual_str.substr(0, 9));
ASSERT_EQ(std::string(":45:06.136"), actual_str.substr(13, 10));
ASSERT_EQ(std::string(":45:06.036"), actual_str.substr(13, 10));
}

TEST(time_utils, time_ms_to_buf)
Expand All @@ -114,5 +114,20 @@ TEST(time_utils, time_ms_to_str)
test_time_ms_to_string(str);
}

TEST(time_utils, time_ms_to_sequent_str)
{
std::string str;
time_ms_to_sequent_string(1605091506036, str);

std::string actual_str(str);

// Time differs between time zones.
//
// The real time 20201111_184506_036 (UTC+8)
// so it must be 2020111x_xx4506_036.
ASSERT_EQ(std::string("2020111"), actual_str.substr(0, 7));
ASSERT_EQ(std::string("4506_036"), actual_str.substr(11, 8));
}

} // namespace utils
} // namespace dsn
15 changes: 13 additions & 2 deletions src/utils/time_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace utils {
auto ret = get_localtime(ts_ms, &tmp);
// NOTE: format_to() does not append a terminating null character, so remember to initialize
// str's memory as zero before.
fmt::format_to(str, "{:%Y-%m-%d %H:%M:%S}.{}", *ret, static_cast<uint32_t>(ts_ms % 1000));
fmt::format_to(str, "{:%Y-%m-%d %H:%M:%S}.{:03}", *ret, static_cast<uint32_t>(ts_ms % 1000));
}

/*extern*/ void time_ms_to_string(uint64_t ts_ms, std::string &str)
Expand All @@ -45,7 +45,18 @@ namespace utils {
struct tm tmp;
auto ret = get_localtime(ts_ms, &tmp);
fmt::format_to(std::back_inserter(str),
"{:%Y-%m-%d %H:%M:%S}.{}",
"{:%Y-%m-%d %H:%M:%S}.{:03}",
*ret,
static_cast<uint32_t>(ts_ms % 1000));
}

/*extern*/ void time_ms_to_sequent_string(uint64_t ts_ms, std::string &str)
{
str.clear();
struct tm tmp;
auto ret = get_localtime(ts_ms, &tmp);
fmt::format_to(std::back_inserter(str),
"{:%Y%m%d_%H%M%S}_{:03}",
*ret,
static_cast<uint32_t>(ts_ms % 1000));
}
Expand Down
5 changes: 4 additions & 1 deletion src/utils/time_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ static struct tm *get_localtime(uint64_t ts_ms, struct tm *tm_buf)
return localtime_r(&t, tm_buf);
}

// get time string, which format is yyyy-MM-dd hh:mm:ss.SSS
// Get time string, which format is yyyy-MM-dd hh:mm:ss.SSS
// NOTE: using char* as output is usually unsafe, remember to initialize its memory as zero before
// calling 'time_ms_to_string'. Please use std::string as the output argument as long as it's
// possible.
extern void time_ms_to_string(uint64_t ts_ms, char *str);
extern void time_ms_to_string(uint64_t ts_ms, std::string &str);

// Get time string, which format is yyyyMMdd_hhmmss_SSS
extern void time_ms_to_sequent_string(uint64_t ts_ms, std::string &str);

// get date string with format of 'yyyy-MM-dd' from given timestamp
inline void time_ms_to_date(uint64_t ts_ms, char *str, int len)
{
Expand Down

0 comments on commit b0033c8

Please sign in to comment.