Write data in output buffers to client. Return C_OK if the client * is still valid after the call, C_ERR if it was freed because of some * error. If handler_installed is set, it will attempt to clear the * write event. * * This function is called by threads, but always with handler_installed * set to 0. So when handler_installed is set to 0 the function must be * thread safe. */
| 1819 | * set to 0. So when handler_installed is set to 0 the function must be |
| 1820 | * thread safe. */ |
| 1821 | int writeToClient(client *c, int handler_installed) { |
| 1822 | /* Update total number of writes on server */ |
| 1823 | g_pserver->stat_total_writes_processed.fetch_add(1, std::memory_order_relaxed); |
| 1824 | |
| 1825 | ssize_t nwritten = 0, totwritten = 0; |
| 1826 | clientReplyBlock *o; |
| 1827 | serverAssertDebug(FCorrectThread(c)); |
| 1828 | |
| 1829 | std::unique_lock<decltype(c->lock)> lock(c->lock); |
| 1830 | |
| 1831 | /* We can only directly read from the replication backlog if the client |
| 1832 | is a replica, so only attempt to do so if that's the case. */ |
| 1833 | if (c->flags & CLIENT_SLAVE && !(c->flags & CLIENT_MONITOR) && c->replstate == SLAVE_STATE_ONLINE) { |
| 1834 | std::unique_lock<fastlock> repl_backlog_lock (g_pserver->repl_backlog_lock); |
| 1835 | // Ensure all writes to the repl backlog are visible |
| 1836 | std::atomic_thread_fence(std::memory_order_acquire); |
| 1837 | |
| 1838 | while (clientHasPendingReplies(c)) { |
| 1839 | long long repl_end_idx = getReplIndexFromOffset(c->repl_end_off); |
| 1840 | serverAssert(c->repl_curr_off != -1); |
| 1841 | |
| 1842 | if (c->repl_curr_off != c->repl_end_off){ |
| 1843 | long long repl_curr_idx = getReplIndexFromOffset(c->repl_curr_off); |
| 1844 | long long nwritten2ndStage = 0; /* How much was written from the start of the replication backlog |
| 1845 | * in the event of a wrap around write */ |
| 1846 | /* normal case with no wrap around */ |
| 1847 | if (repl_end_idx >= repl_curr_idx){ |
| 1848 | nwritten = connWrite(c->conn, g_pserver->repl_backlog + repl_curr_idx, repl_end_idx - repl_curr_idx); |
| 1849 | /* wrap around case */ |
| 1850 | } else { |
| 1851 | nwritten = connWrite(c->conn, g_pserver->repl_backlog + repl_curr_idx, g_pserver->repl_backlog_size - repl_curr_idx); |
| 1852 | /* only attempt wrapping if we write the correct number of bytes */ |
| 1853 | if (nwritten == g_pserver->repl_backlog_size - repl_curr_idx){ |
| 1854 | nwritten2ndStage = connWrite(c->conn, g_pserver->repl_backlog, repl_end_idx); |
| 1855 | if (nwritten2ndStage != -1) |
| 1856 | nwritten += nwritten2ndStage; |
| 1857 | } |
| 1858 | } |
| 1859 | |
| 1860 | /* only increment bytes if an error didn't occur */ |
| 1861 | if (nwritten > 0){ |
| 1862 | totwritten += nwritten; |
| 1863 | c->repl_curr_off += nwritten; |
| 1864 | serverAssert(c->repl_curr_off <= c->repl_end_off); |
| 1865 | } |
| 1866 | |
| 1867 | /* If the second part of a write didn't go through, we still need to register that */ |
| 1868 | if (nwritten2ndStage == -1) nwritten = -1; |
| 1869 | if (nwritten == -1) |
| 1870 | break; |
| 1871 | } else { |
| 1872 | break; |
| 1873 | } |
| 1874 | } |
| 1875 | } else { |
| 1876 | while(clientHasPendingReplies(c)) { |
| 1877 | if (c->bufpos > 0) { |
| 1878 | auto bufpos = c->bufpos; |
no test coverage detected