1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #pragma once
25 
26 #include "tscore/ink_platform.h"
27 #include "tscore/Diags.h"
28 #include "LogFormat.h"
29 #include "LogLimits.h"
30 #include "LogAccess.h"
31 
32 class LogObject;
33 class LogConfig;
34 class LogBufferIterator;
35 
36 #define LOG_SEGMENT_COOKIE 0xaceface
37 #define LOG_SEGMENT_VERSION 2
38 
39 #if defined(linux)
40 #define LB_DEFAULT_ALIGN 512
41 #else
42 #define LB_DEFAULT_ALIGN 8
43 #endif
44 
45 /*-------------------------------------------------------------------------
46   LogEntryHeader
47 
48   This struct is automatically laid down at the head of each entry in the
49   buffer.
50   -------------------------------------------------------------------------*/
51 
52 struct LogEntryHeader {
53   int64_t timestamp;      // the seconds portion of the timestamp
54   int32_t timestamp_usec; // the microseconds portion of the timestamp
55   uint32_t entry_len;
56 };
57 
58 /*-------------------------------------------------------------------------
59   LogBufferHeader
60 
61   This struct is automatically laid down at the head of each buffer.
62   -------------------------------------------------------------------------*/
63 
64 struct LogBufferHeader {
65   uint32_t cookie;               // so we can find it on disk
66   uint32_t version;              // in case we want to change it later
67   uint32_t format_type;          // SQUID_LOG, COMMON_LOG, ...
68   uint32_t byte_count;           // actual # of bytes for the segment
69   uint32_t entry_count;          // actual number of entries stored
70   uint32_t low_timestamp;        // lowest timestamp value of entries
71   uint32_t high_timestamp;       // highest timestamp value of entries
72   uint32_t log_object_flags;     // log object flags
73   uint64_t log_object_signature; // log object signature
74 #if defined(LOG_BUFFER_TRACKING)
75   uint32_t int id;
76 #endif // defined(LOG_BUFFER_TRACKING)
77 
78   // all offsets are computed from the start of the buffer (ie, "this"),
79   // and so any valid offset will be at least sizeof(LogBufferHeader).
80 
81   uint32_t fmt_name_offset;      // offset to format name string
82   uint32_t fmt_fieldlist_offset; // offset to format fieldlist string
83   uint32_t fmt_printf_offset;    // offset to format printf string
84   uint32_t src_hostname_offset;  // offset to source (client) hostname
85   uint32_t log_filename_offset;  // offset to log filename
86   uint32_t data_offset;          // offset to start of data entry
87   // section
88 
89   // some helper functions to return the header strings
90 
91   char *fmt_fieldlist();
92   char *fmt_printf();
93   char *src_hostname();
94   char *log_filename();
95 };
96 
97 union LB_State {
LB_State()98   LB_State() : ival(0) {}
LB_State(LB_State & vs)99   LB_State(LB_State &vs) { ival = vs.ival; }
100   LB_State &
101   operator=(LB_State &vs)
102   {
103     ival = vs.ival;
104     return *this;
105   }
106 
107   int64_t ival; // ival is used to help do an atomic CAS for struct s
108   struct {
109     uint32_t offset;           // buffer offset(bytes in buffer)
110     uint16_t num_entries;      // number of entries in buffer
111     uint16_t full : 1;         // not accepting more checkouts
112     uint16_t num_writers : 15; // number of writers
113   } s;
114 };
115 
116 /*-------------------------------------------------------------------------
117   LogBuffer
118   -------------------------------------------------------------------------*/
119 class LogBuffer
120 {
121 public:
122   SLINK(LogBuffer, write_link);
123   enum LB_ResultCode {
124     LB_OK = 0,
125     LB_FULL_NO_WRITERS,
126     LB_FULL_ACTIVE_WRITERS,
127     LB_RETRY,
128     LB_ALL_WRITERS_DONE,
129     LB_BUSY,
130     LB_BUFFER_TOO_SMALL
131   };
132 
133   LogBuffer(const LogConfig *cfg, LogObject *owner, size_t size, size_t buf_align = LB_DEFAULT_ALIGN,
134             size_t write_align = INK_MIN_ALIGN);
135   LogBuffer(LogObject *owner, LogBufferHeader *header);
136   ~LogBuffer();
137 
138   char &
139   operator[](int idx)
140   {
141     ink_assert(idx >= 0);
142     ink_assert((size_t)idx < m_size);
143     return m_buffer[idx];
144   }
145 
146   int
switch_state(LB_State & old_state,LB_State & new_state)147   switch_state(LB_State &old_state, LB_State &new_state)
148   {
149     INK_WRITE_MEMORY_BARRIER;
150     return (ink_atomic_cas(&m_state.ival, old_state.ival, new_state.ival));
151   }
152 
153   LB_ResultCode checkout_write(size_t *write_offset, size_t write_size);
154   LB_ResultCode checkin_write(size_t write_offset);
155   void force_full();
156 
157   LogBufferHeader *
header()158   header() const
159   {
160     return m_header;
161   }
162 
163   long
expiration_time()164   expiration_time() const
165   {
166     return m_expiration_time;
167   }
168 
169   // this should only be called when buffer is ready to be flushed
170   void update_header_data();
171 
172   uint32_t
get_id()173   get_id() const
174   {
175     return m_id;
176   }
177 
178   LogObject *
get_owner()179   get_owner() const
180   {
181     return m_owner;
182   }
183 
184   LINK(LogBuffer, link);
185 
186   // static variables
187   static int32_t M_ID;
188 
189   // static functions
190   static size_t max_entry_bytes();
191   static int to_ascii(LogEntryHeader *entry, LogFormatType type, char *buf, int max_len, const char *symbol_str, char *printf_str,
192                       unsigned buffer_version, const char *alt_format = nullptr);
193   static int resolve_custom_entry(LogFieldList *fieldlist, char *printf_str, char *read_from, char *write_to, int write_to_len,
194                                   long timestamp, long timestamp_us, unsigned buffer_version, LogFieldList *alt_fieldlist = nullptr,
195                                   char *alt_printf_str = nullptr);
196 
197   static void
destroy(LogBuffer * & lb)198   destroy(LogBuffer *&lb)
199   {
200     // ink_atomic_increment() returns the previous value, so when it was 1, we are
201     // the thread that decremented to zero and should delete ...
202     int refcnt = ink_atomic_increment(&lb->m_references, -1);
203 
204     if (refcnt == 1) {
205       delete lb;
206       lb = nullptr;
207     }
208 
209     ink_release_assert(refcnt >= 0);
210   }
211 
212 private:
213   char *m_unaligned_buffer;         // the unaligned buffer
214   char *m_buffer;                   // the buffer
215   size_t m_size;                    // the buffer size
216   size_t m_buf_align;               // the buffer alignment
217   size_t m_write_align;             // the write alignment mask
218   int m_buffer_fast_allocator_size; // indicates whether the logbuffer is allocated from ioBuf
219 
220   long m_expiration_time; // buffer expiration time
221 
222   LogObject *m_owner; // the LogObject that owns this buf.
223   LogBufferHeader *m_header;
224 
225   uint32_t m_id; // unique buffer id (for debugging)
226 public:
227   LB_State m_state; // buffer state
228   int m_references; // outstanding checkout_write references.
229 
230   // noncopyable
231   // -- member functions that are not allowed --
232   LogBuffer(const LogBuffer &rhs) = delete;
233   LogBuffer &operator=(const LogBuffer &rhs) = delete;
234 
235 private:
236   // private functions
237   size_t _add_buffer_header(const LogConfig *cfg);
238   unsigned add_header_str(const char *str, char *buf_ptr, unsigned buf_len);
239   void freeLogBuffer();
240 
241   // -- member functions that are not allowed --
242   LogBuffer();
243 
244   friend class LogBufferIterator;
245 };
246 
247 class LogFile;
248 
249 /*-------------------------------------------------------------------------
250   LogBufferList
251 
252   Support atomic operations on a list of LogBuffer objects.
253   -------------------------------------------------------------------------*/
254 
255 class LogBufferList
256 {
257 private:
258   Queue<LogBuffer> m_buffer_list;
259   ink_mutex m_mutex;
260   int m_size;
261 
262 public:
263   LogBufferList();
264   ~LogBufferList();
265 
266   void add(LogBuffer *lb);
267   LogBuffer *get();
268   int
get_size()269   get_size()
270   {
271     return m_size;
272   }
273 };
274 
275 /*-------------------------------------------------------------------------
276   LogBufferIterator
277 
278   This class will iterate over the entries in a LogBuffer.
279   -------------------------------------------------------------------------*/
280 
281 class LogBufferIterator
282 {
283 public:
284   LogBufferIterator(LogBufferHeader *header, bool in_network_order = false);
285   ~LogBufferIterator();
286 
287   LogEntryHeader *next();
288 
289   // noncopyable
290   // -- member functions not allowed --
291   LogBufferIterator(const LogBufferIterator &) = delete;
292   LogBufferIterator &operator=(const LogBufferIterator &) = delete;
293 
294 private:
295   bool m_in_network_order;
296   char *m_next;
297   unsigned m_iter_entry_count;
298   unsigned m_buffer_entry_count;
299 
300   // -- member functions not allowed --
301   LogBufferIterator();
302 };
303 
304 /*-------------------------------------------------------------------------
305   LogBufferIterator
306 
307   This class provides the ability to iterate over the LogEntries stored
308   within a given LogBuffer.
309   -------------------------------------------------------------------------*/
310 
LogBufferIterator(LogBufferHeader * header,bool in_network_order)311 inline LogBufferIterator::LogBufferIterator(LogBufferHeader *header, bool in_network_order)
312   : m_in_network_order(in_network_order), m_next(nullptr), m_iter_entry_count(0), m_buffer_entry_count(0)
313 {
314   ink_assert(header);
315 
316   switch (header->version) {
317   case LOG_SEGMENT_VERSION:
318     m_next               = (char *)header + header->data_offset;
319     m_buffer_entry_count = header->entry_count;
320     break;
321 
322   default:
323     Note("Invalid LogBuffer version %d in LogBufferIterator; "
324          "current version is %d",
325          header->version, LOG_SEGMENT_VERSION);
326     break;
327   }
328 }
329 
330 /*-------------------------------------------------------------------------
331   -------------------------------------------------------------------------*/
332 
~LogBufferIterator()333 inline LogBufferIterator::~LogBufferIterator() {}
334