added iOS source code
[wl-app.git] / iOS / Pods / Realm / include / core / realm / group_writer.hpp
1 /*************************************************************************
2  *
3  * Copyright 2016 Realm Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  **************************************************************************/
18
19 #ifndef REALM_GROUP_WRITER_HPP
20 #define REALM_GROUP_WRITER_HPP
21
22 #include <cstdint> // unint8_t etc
23 #include <utility>
24
25 #include <realm/util/file.hpp>
26 #include <realm/alloc.hpp>
27 #include <realm/impl/array_writer.hpp>
28 #include <realm/array_integer.hpp>
29
30
31 namespace realm {
32
33 // Pre-declarations
34 class Group;
35 class SlabAlloc;
36
37
38 /// This class is not supposed to be reused for multiple write sessions. In
39 /// particular, do not reuse it in case any of the functions throw.
40 ///
41 /// FIXME: Move this class to namespace realm::_impl and to subdir src/realm/impl.
42 class GroupWriter : public _impl::ArrayWriterBase {
43 public:
44     // For groups in transactional mode (Group::m_is_shared), this constructor
45     // must be called while a write transaction is in progress.
46     //
47     // The constructor adds free-space tracking information to the specified
48     // group, if it is not already present (4th and 5th entry in
49     // Group::m_top). If the specified group is in transactional mode
50     // (Group::m_is_shared), the constructor also adds version tracking
51     // information to the group, if it is not already present (6th and 7th entry
52     // in Group::m_top).
53     GroupWriter(Group&);
54     ~GroupWriter();
55
56     void set_versions(uint64_t current, uint64_t read_lock) noexcept;
57
58     /// Write all changed array nodes into free space.
59     ///
60     /// Returns the new top ref. When in full durability mode, call
61     /// commit() with the returned top ref.
62     ref_type write_group();
63
64     /// Flush changes to physical medium, then write the new top ref
65     /// to the file header, then flush again. Pass the top ref
66     /// returned by write_group().
67     void commit(ref_type new_top_ref);
68
69     size_t get_file_size() const noexcept;
70
71     /// Write the specified chunk into free space.
72     void write(const char* data, size_t size);
73
74     ref_type write_array(const char*, size_t, uint32_t) override;
75
76 #ifdef REALM_DEBUG
77     void dump();
78 #endif
79
80     size_t get_free_space();
81 private:
82     class MapWindow;
83     Group& m_group;
84     SlabAlloc& m_alloc;
85     ArrayInteger m_free_positions; // 4th slot in Group::m_top
86     ArrayInteger m_free_lengths;   // 5th slot in Group::m_top
87     ArrayInteger m_free_versions;  // 6th slot in Group::m_top
88     uint64_t m_current_version;
89     uint64_t m_readlock_version;
90     size_t m_alloc_position;
91
92     // Currently cached memory mappings. We keep as many as 16 1MB windows
93     // open for writing. The allocator will favor sequential allocation
94     // from a modest number of windows, depending upon fragmentation, so
95     // 16 windows should be more than enough. If more than 16 windows are
96     // needed, the least recently used is sync'ed and closed to make room
97     // for a new one. The windows are kept in MRU (most recently used) order.
98     const static int num_map_windows = 16;
99     std::vector<std::unique_ptr<MapWindow>> m_map_windows;
100
101     // Get a suitable memory mapping for later access:
102     // potentially adding it to the cache, potentially closing
103     // the least recently used and sync'ing it to disk
104     MapWindow* get_window(ref_type start_ref, size_t size);
105
106     // Sync all cached memory mappings
107     void sync_all_mappings();
108
109     // Merge adjacent chunks
110     void merge_free_space();
111
112     /// Allocate a chunk of free space of the specified size. The
113     /// specified size must be 8-byte aligned. Extend the file if
114     /// required. The returned chunk is removed from the amount of
115     /// remaing free space. The returned chunk is guaranteed to be
116     /// within a single contiguous memory mapping.
117     ///
118     /// \return The position within the database file of the allocated
119     /// chunk.
120     size_t get_free_space(size_t size);
121
122     /// Find a block of free space that is at least as big as the
123     /// specified size and which will allow an allocation that is mapped
124     /// inside a contiguous address range. The specified size does not
125     /// need to be 8-byte aligned. Extend the file if required.
126     /// The returned chunk is not removed from the amount of remaing
127     /// free space.
128     ///
129     /// \return A pair (`chunk_ndx`, `chunk_size`) where `chunk_ndx`
130     /// is the index of a chunk whose size is at least the requestd
131     /// size, and `chunk_size` is the size of that chunk.
132     std::pair<size_t, size_t> reserve_free_space(size_t size);
133
134     /// Search only a range of the free list for a block as big as the
135     /// specified size. Return a pair with index and size of the found chunk.
136     /// \param found indicates whether a suitable block was found.
137     std::pair<size_t, size_t> search_free_space_in_part_of_freelist(size_t size, size_t begin, size_t end,
138                                                                     bool& found);
139
140     /// Extend the file to ensure that a chunk of free space of the
141     /// specified size is available. The specified size does not need
142     /// to be 8-byte aligned. This function guarantees that it will
143     /// add at most one entry to the free-lists.
144     ///
145     /// \return A pair (`chunk_ndx`, `chunk_size`) where `chunk_ndx`
146     /// is the index of a chunk whose size is at least the requestd
147     /// size, and `chunk_size` is the size of that chunk.
148     std::pair<size_t, size_t> extend_free_space(size_t requested_size);
149
150     void write_array_at(MapWindow* window, ref_type, const char* data, size_t size);
151     size_t split_freelist_chunk(size_t index, size_t start_pos, size_t alloc_pos, size_t chunk_size, bool is_shared);
152 };
153
154
155 // Implementation:
156
157 inline void GroupWriter::set_versions(uint64_t current, uint64_t read_lock) noexcept
158 {
159     REALM_ASSERT(read_lock <= current);
160     m_current_version = current;
161     m_readlock_version = read_lock;
162 }
163
164 } // namespace realm
165
166 #endif // REALM_GROUP_WRITER_HPP