1 /*
2  * Copyright (C) 2010-2020 Codership Oy <info@codership.com>
3  */
4 
5 /*! @file ring buffer storage class */
6 
7 #ifndef _gcache_rb_store_hpp_
8 #define _gcache_rb_store_hpp_
9 
10 #include "gcache_memops.hpp"
11 #include "gcache_bh.hpp"
12 #include "gcache_types.hpp"
13 
14 #include <gu_fdesc.hpp>
15 #include <gu_mmap.hpp>
16 #include <gu_uuid.hpp>
17 
18 #include <string>
19 
20 namespace gcache
21 {
22     class RingBuffer : public MemOps
23     {
24     public:
25 
26         RingBuffer (const std::string& name,
27                     size_t             size,
28                     seqno2ptr_t&       seqno2ptr,
29                     gu::UUID&          gid,
30                     int                dbg,
31                     bool               recover);
32 
33         ~RingBuffer ();
34 
35         void* malloc  (size_type size);
36 
37         void  free    (BufferHeader* bh);
38 
39         void* realloc (void* ptr, size_type size);
40 
discard(BufferHeader * const bh)41         void  discard (BufferHeader* const bh)
42         {
43             assert (BH_is_released(bh));
44             assert (SEQNO_ILL == bh->seqno_g);
45             size_free_ += bh->size;
46             assert (size_free_ <= size_cache_);
47         }
48 
size() const49         size_t size      () const { return size_cache_; }
50 
rb_size() const51         size_t rb_size   () const { return fd_.size(); }
52 
rb_name() const53         const std::string& rb_name() const { return fd_.name(); }
54 
55         void  reset();
56 
57         void  seqno_reset();
58 
59         /* returns true when successfully discards all seqnos in range */
60         bool  discard_seqnos(seqno2ptr_t::iterator i_begin,
61                              seqno2ptr_t::iterator i_end);
62 
63         /* returns true when successfully discards all seqnos up to s */
discard_seqno(seqno_t s)64         bool  discard_seqno(seqno_t s)
65         {
66             return discard_seqnos(seqno2ptr_.begin(), seqno2ptr_.find(s + 1));
67         }
68 
69         void print (std::ostream& os) const;
70 
pad_size()71         static size_t pad_size()
72         {
73             RingBuffer* rb(0);
74             // cppcheck-suppress nullPointer
75             return (PREAMBLE_LEN * sizeof(*(rb->preamble_)) +
76                     // cppcheck-suppress nullPointer
77                     HEADER_LEN   * sizeof(*(rb->header_)));
78         }
79 
assert_size_free() const80         void assert_size_free() const
81         {
82 #ifndef NDEBUG
83             if (next_ >= first_)
84             {
85                 /* start_  first_      next_    end_
86                  *   |       |###########|       |      */
87                 assert(size_free_ >= (size_cache_ - (next_ - first_)));
88             }
89             else
90             {
91                 /* start_  next_       first_   end_
92                  *   |#######|           |#####| |      */
93                 assert(size_free_ >= size_t(first_ - next_));
94             }
95             assert (size_free_ <= size_cache_);
96 #endif
97         }
98 
assert_size_trail() const99         void assert_size_trail() const
100         {
101 #ifndef NDEBUG
102             if (next_ >= first_)
103                 assert(0 == size_trail_);
104             else
105                 assert(size_trail_ >= sizeof(BufferHeader));
106 #endif
107         }
108 
assert_sizes() const109         void assert_sizes() const
110         {
111             assert_size_trail();
112             assert_size_free();
113         }
114 
set_debug(int const dbg)115         void set_debug(int const dbg) { debug_ = dbg & DEBUG; }
116 
117 #ifdef GCACHE_RB_UNIT_TEST
offset(const void * const ptr) const118         ptrdiff_t offset(const void* const ptr) const
119         {
120             return static_cast<const uint8_t*>(ptr) - start_;
121         }
122 #endif
123 
124     private:
125 
126         static size_t const PREAMBLE_LEN = 1024;
127         static size_t const HEADER_LEN = 32;
128 
129         // 0 - undetermined version
130         // 1 - initial version, no buffer alignment
131         // 2 - buffer alignemnt to GU_WORD_BYTES
132         static int    const VERSION = 2;
133 
134         static int    const DEBUG = 2; // debug flag
135 
136         gu::FileDescriptor fd_;
137         gu::MMap           mmap_;
138         char*        const preamble_; // ASCII text preamble
139         int64_t*     const header_;   // cache binary header
140         uint8_t*     const start_;    // start of cache area
141         uint8_t*     const end_;      // first byte after cache area
142         uint8_t*           first_;    // pointer to the first (oldest) buffer
143         uint8_t*           next_;     // pointer to the next free space
144 
145         seqno2ptr_t&       seqno2ptr_;
146         gu::UUID&          gid_;
147 
148         size_t       const size_cache_;
149         size_t             size_free_;
150         size_t             size_used_;
151         size_t             size_trail_;
152 
153         int                debug_;
154 
155         bool               open_;
156 
157         BufferHeader* get_new_buffer (size_type size);
158 
159         void          constructor_common();
160 
161         /* preamble fields */
162         static std::string const PR_KEY_VERSION;
163         static std::string const PR_KEY_GID;
164         static std::string const PR_KEY_SEQNO_MAX;
165         static std::string const PR_KEY_SEQNO_MIN;
166         static std::string const PR_KEY_OFFSET;
167         static std::string const PR_KEY_SYNCED;
168 
169         void          write_preamble(bool synced);
170         void          open_preamble(bool recover);
171         void          close_preamble();
172 
173         // returns lower bound (not inclusive) of valid seqno range
174         seqno_t       scan(off_t offset, int scan_step);
175         void          recover(off_t offset, int version);
176 
177         void          estimate_space();
178 
179         RingBuffer(const gcache::RingBuffer&);
180         RingBuffer& operator=(const gcache::RingBuffer&);
181 
182 #ifdef GCACHE_RB_UNIT_TEST
183     public:
start() const184         uint8_t* start() const { return start_; }
185 #endif
186     };
187 
operator <<(std::ostream & os,const RingBuffer & rb)188     inline std::ostream& operator<< (std::ostream& os, const RingBuffer& rb)
189     {
190         rb.print(os);
191         return os;
192     }
193 
194 } /* namespace gcache */
195 
196 #endif /* _gcache_rb_store_hpp_ */
197