| 340 | } |
| 341 | |
| 342 | LogBuffer * |
| 343 | LogObject::_checkout_write(size_t *write_offset, size_t bytes_needed) |
| 344 | { |
| 345 | LogBuffer::LB_ResultCode result_code; |
| 346 | LogBuffer *buffer; |
| 347 | LogBuffer *new_buffer = nullptr; |
| 348 | bool retry = true; |
| 349 | head_p old_h; |
| 350 | |
| 351 | do { |
| 352 | // To avoid a race condition, we keep a count of held references in |
| 353 | // the pointer itself and add this to m_outstanding_references. |
| 354 | |
| 355 | // Increment the version of m_log_buffer, returning the previous version. |
| 356 | head_p h = increment_pointer_version(&m_log_buffer); |
| 357 | |
| 358 | buffer = static_cast<LogBuffer *>(FREELIST_POINTER(h)); |
| 359 | result_code = buffer->checkout_write(write_offset, bytes_needed); |
| 360 | bool decremented = false; |
| 361 | |
| 362 | switch (result_code) { |
| 363 | case LogBuffer::LB_OK: |
| 364 | // checkout succeeded |
| 365 | retry = false; |
| 366 | break; |
| 367 | |
| 368 | case LogBuffer::LB_FULL_ACTIVE_WRITERS: |
| 369 | case LogBuffer::LB_FULL_NO_WRITERS: |
| 370 | // no more room in current buffer, create a new one |
| 371 | new_buffer = new LogBuffer(Log::config, this, Log::config->log_buffer_size); |
| 372 | |
| 373 | // swap the new buffer for the old one |
| 374 | INK_WRITE_MEMORY_BARRIER; |
| 375 | |
| 376 | do { |
| 377 | INK_QUEUE_LD(old_h, m_log_buffer); |
| 378 | // we may depend on comparing the old pointer to the new pointer to detect buffer swaps |
| 379 | // without worrying about pointer collisions because we always allocate a new LogBuffer |
| 380 | // before freeing the old one |
| 381 | if (FREELIST_POINTER(old_h) != FREELIST_POINTER(h)) { |
| 382 | ink_atomic_increment(&buffer->m_references, -1); |
| 383 | |
| 384 | // another thread is already creating a new buffer, |
| 385 | // so delete new_buffer and try again next loop iteration |
| 386 | delete new_buffer; |
| 387 | new_buffer = nullptr; |
| 388 | break; |
| 389 | } |
| 390 | } while (write_pointer_version(&m_log_buffer, old_h, new_buffer, 0) == false); |
| 391 | |
| 392 | if (FREELIST_POINTER(old_h) == FREELIST_POINTER(h)) { |
| 393 | ink_atomic_increment(&buffer->m_references, FREELIST_VERSION(old_h) - 1); |
| 394 | |
| 395 | int idx = m_buffer_manager_idx++ % m_flush_threads; |
| 396 | Dbg(dbg_ctl_log_logbuffer, "adding buffer %d to flush list after checkout", buffer->get_id()); |
| 397 | m_buffer_manager[idx].add_to_flush_queue(buffer); |
| 398 | Log::preproc_notify[idx].signal(); |
| 399 | buffer = nullptr; |
nothing calls this directly
no test coverage detected