1 // Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 // This source code is licensed under both the GPLv2 (found in the
3 // COPYING file in the root directory) and Apache 2.0 License
4 // (found in the LICENSE.Apache file in the root directory).
5 
6 // WAL related classes used in VersionEdit and VersionSet.
7 // Modifications to WalAddition and WalDeletion may need to update
8 // VersionEdit and its related tests.
9 
10 #pragma once
11 
12 #include <map>
13 #include <ostream>
14 #include <string>
15 #include <unordered_map>
16 #include <vector>
17 
18 #include "logging/event_logger.h"
19 #include "port/port.h"
20 #include "rocksdb/rocksdb_namespace.h"
21 
22 namespace ROCKSDB_NAMESPACE {
23 
24 class JSONWriter;
25 class Slice;
26 class Status;
27 
28 using WalNumber = uint64_t;
29 
30 // Metadata of a WAL.
31 class WalMetadata {
32  public:
33   WalMetadata() = default;
34 
WalMetadata(uint64_t synced_size_bytes)35   explicit WalMetadata(uint64_t synced_size_bytes)
36       : synced_size_bytes_(synced_size_bytes) {}
37 
HasSyncedSize()38   bool HasSyncedSize() const { return synced_size_bytes_ != kUnknownWalSize; }
39 
SetSyncedSizeInBytes(uint64_t bytes)40   void SetSyncedSizeInBytes(uint64_t bytes) { synced_size_bytes_ = bytes; }
41 
GetSyncedSizeInBytes()42   uint64_t GetSyncedSizeInBytes() const { return synced_size_bytes_; }
43 
44  private:
45   // The size of WAL is unknown, used when the WAL is not synced yet or is
46   // empty.
47   constexpr static uint64_t kUnknownWalSize = port::kMaxUint64;
48 
49   // Size of the most recently synced WAL in bytes.
50   uint64_t synced_size_bytes_ = kUnknownWalSize;
51 };
52 
53 // These tags are persisted to MANIFEST, so it's part of the user API.
54 enum class WalAdditionTag : uint32_t {
55   // Indicates that there are no more tags.
56   kTerminate = 1,
57   // Synced Size in bytes.
58   kSyncedSize = 2,
59   // Add tags in the future, such as checksum?
60 };
61 
62 // Records the event of adding a WAL in VersionEdit.
63 class WalAddition {
64  public:
WalAddition()65   WalAddition() : number_(0), metadata_() {}
66 
WalAddition(WalNumber number)67   explicit WalAddition(WalNumber number) : number_(number), metadata_() {}
68 
WalAddition(WalNumber number,WalMetadata meta)69   WalAddition(WalNumber number, WalMetadata meta)
70       : number_(number), metadata_(std::move(meta)) {}
71 
GetLogNumber()72   WalNumber GetLogNumber() const { return number_; }
73 
GetMetadata()74   const WalMetadata& GetMetadata() const { return metadata_; }
75 
76   void EncodeTo(std::string* dst) const;
77 
78   Status DecodeFrom(Slice* src);
79 
80   std::string DebugString() const;
81 
82  private:
83   WalNumber number_;
84   WalMetadata metadata_;
85 };
86 
87 std::ostream& operator<<(std::ostream& os, const WalAddition& wal);
88 JSONWriter& operator<<(JSONWriter& jw, const WalAddition& wal);
89 
90 using WalAdditions = std::vector<WalAddition>;
91 
92 // Records the event of deleting WALs before the specified log number.
93 class WalDeletion {
94  public:
WalDeletion()95   WalDeletion() : number_(kEmpty) {}
96 
WalDeletion(WalNumber number)97   explicit WalDeletion(WalNumber number) : number_(number) {}
98 
GetLogNumber()99   WalNumber GetLogNumber() const { return number_; }
100 
101   void EncodeTo(std::string* dst) const;
102 
103   Status DecodeFrom(Slice* src);
104 
105   std::string DebugString() const;
106 
IsEmpty()107   bool IsEmpty() const { return number_ == kEmpty; }
108 
Reset()109   void Reset() { number_ = kEmpty; }
110 
111  private:
112   static constexpr WalNumber kEmpty = 0;
113 
114   WalNumber number_;
115 };
116 
117 std::ostream& operator<<(std::ostream& os, const WalDeletion& wal);
118 JSONWriter& operator<<(JSONWriter& jw, const WalDeletion& wal);
119 
120 // Used in VersionSet to keep the current set of WALs.
121 //
122 // When a WAL is synced or becomes obsoleted,
123 // a VersionEdit is logged to MANIFEST and
124 // the WAL is added to or deleted from WalSet.
125 //
126 // Not thread safe, needs external synchronization such as holding DB mutex.
127 class WalSet {
128  public:
129   // Add WAL(s).
130   // If the WAL is closed,
131   // then there must be an existing unclosed WAL,
132   // otherwise, return Status::Corruption.
133   // Can happen when applying a VersionEdit or recovering from MANIFEST.
134   Status AddWal(const WalAddition& wal);
135   Status AddWals(const WalAdditions& wals);
136 
137   // Delete WALs with log number smaller than the specified wal number.
138   // Can happen when applying a VersionEdit or recovering from MANIFEST.
139   Status DeleteWalsBefore(WalNumber wal);
140 
141   // Resets the internal state.
142   void Reset();
143 
144   // WALs with number less than MinWalNumberToKeep should not exist in WalSet.
GetMinWalNumberToKeep()145   WalNumber GetMinWalNumberToKeep() const { return min_wal_number_to_keep_; }
146 
GetWals()147   const std::map<WalNumber, WalMetadata>& GetWals() const { return wals_; }
148 
149   // Checks whether there are missing or corrupted WALs.
150   // Returns Status::OK if there is no missing nor corrupted WAL,
151   // otherwise returns Status::Corruption.
152   // logs_on_disk is a map from log number to the log filename.
153   // Note that logs_on_disk may contain logs that is obsolete but
154   // haven't been deleted from disk.
155   Status CheckWals(
156       Env* env,
157       const std::unordered_map<WalNumber, std::string>& logs_on_disk) const;
158 
159  private:
160   std::map<WalNumber, WalMetadata> wals_;
161   // WAL number < min_wal_number_to_keep_ should not exist in wals_.
162   // It's monotonically increasing, in-memory only, not written to MANIFEST.
163   WalNumber min_wal_number_to_keep_ = 0;
164 };
165 
166 }  // namespace ROCKSDB_NAMESPACE
167