1
#include "source/extensions/key_value/file_based/config.h"
2

            
3
#include "envoy/registry/registry.h"
4

            
5
namespace Envoy {
6
namespace Extensions {
7
namespace KeyValue {
8

            
9
FileBasedKeyValueStore::FileBasedKeyValueStore(Event::Dispatcher& dispatcher,
10
                                               std::chrono::milliseconds flush_interval,
11
                                               Filesystem::Instance& file_system,
12
                                               const std::string& filename, uint32_t max_entries)
13
123
    : KeyValueStoreBase(dispatcher, flush_interval, max_entries), file_system_(file_system),
14
123
      filename_(filename) {
15
123
  if (!file_system_.fileExists(filename_)) {
16
73
    ENVOY_LOG(info, "File for key value store does not yet exist: {}", filename);
17
73
    return;
18
73
  }
19
50
  auto file_or_error = file_system_.fileReadToEnd(filename_);
20
50
  THROW_IF_NOT_OK_REF(file_or_error.status());
21
50
  const std::string contents = file_or_error.value();
22
50
  if (!parseContents(contents)) {
23
4
    ENVOY_LOG(warn, "Failed to parse key value store file {}", filename);
24
4
  }
25
50
}
26

            
27
138
void FileBasedKeyValueStore::flush() {
28
138
  static constexpr Filesystem::FlagSet DefaultFlags{1 << Filesystem::File::Operation::Write |
29
138
                                                    1 << Filesystem::File::Operation::Create};
30
138
  Filesystem::FilePathAndType file_info{Filesystem::DestinationType::File, filename_};
31
138
  auto file = file_system_.createFile(file_info);
32
138
  if (!file || !file->open(DefaultFlags).return_value_) {
33
1
    ENVOY_LOG(error, "Failed to flush cache to file {}", filename_);
34
1
    return;
35
1
  }
36
150
  for (const auto& [key, value_with_ttl] : store()) {
37
140
    file->write(absl::StrCat(key.length(), "\n"));
38
140
    file->write(key);
39
140
    file->write(absl::StrCat(value_with_ttl.value_.length(), "\n"));
40
140
    file->write(value_with_ttl.value_);
41
140
    if (value_with_ttl.ttl_.has_value()) {
42
2
      std::string ttl = std::to_string(value_with_ttl.ttl_.value().count());
43
2
      file->write(KV_STORE_TTL_KEY);
44
2
      file->write(absl::StrCat(ttl.length(), "\n"));
45
2
      file->write(ttl);
46
2
    }
47
140
  }
48
137
  file->close();
49
137
}
50

            
51
KeyValueStorePtr FileBasedKeyValueStoreFactory::createStore(
52
    const Protobuf::Message& config, ProtobufMessage::ValidationVisitor& validation_visitor,
53
101
    Event::Dispatcher& dispatcher, Filesystem::Instance& file_system) {
54
101
  const auto& typed_config = MessageUtil::downcastAndValidate<
55
101
      const envoy::config::common::key_value::v3::KeyValueStoreConfig&>(config, validation_visitor);
56
101
  const auto file_config = MessageUtil::anyConvertAndValidate<
57
101
      envoy::extensions::key_value::file_based::v3::FileBasedKeyValueStoreConfig>(
58
101
      typed_config.config().typed_config(), validation_visitor);
59
101
  const auto milliseconds =
60
101
      std::chrono::milliseconds(DurationUtil::durationToMilliseconds(file_config.flush_interval()));
61
101
  const uint32_t max_entries = PROTOBUF_GET_WRAPPED_OR_DEFAULT(file_config, max_entries, 1000);
62
101
  return std::make_unique<FileBasedKeyValueStore>(dispatcher, milliseconds, file_system,
63
101
                                                  file_config.filename(), max_entries);
64
101
}
65

            
66
REGISTER_FACTORY(FileBasedKeyValueStoreFactory, KeyValueStoreFactory);
67

            
68
} // namespace KeyValue
69
} // namespace Extensions
70
} // namespace Envoy