Commit 121e04dec421ee4f23dd91bcbf2abb035001daff

Authored by Wiebe Cazemier
1 parent ae95e6dc

Circbuf for write buffer

cirbuf.cpp
@@ -25,13 +25,13 @@ CirBuf::~CirBuf() @@ -25,13 +25,13 @@ CirBuf::~CirBuf()
25 free(buf); 25 free(buf);
26 } 26 }
27 27
28 -int CirBuf::usedBytes() const 28 +uint CirBuf::usedBytes() const
29 { 29 {
30 int result = (head - tail) & (size-1); 30 int result = (head - tail) & (size-1);
31 return result; 31 return result;
32 } 32 }
33 33
34 -int CirBuf::freeSpace() const 34 +uint CirBuf::freeSpace() const
35 { 35 {
36 int result = (tail - (head + 1)) & (size-1); 36 int result = (tail - (head + 1)) & (size-1);
37 return result; 37 return result;
@@ -99,7 +99,7 @@ void CirBuf::doubleSize() @@ -99,7 +99,7 @@ void CirBuf::doubleSize()
99 head = tail + usedBytes(); 99 head = tail + usedBytes();
100 size = newSize; 100 size = newSize;
101 101
102 - std::cout << "New read buf size: " << size << std::endl; 102 + std::cout << "New buf size: " << size << std::endl;
103 103
104 #ifdef TESTING 104 #ifdef TESTING
105 memset(&buf[head], 5, maxWriteSize() + 2); 105 memset(&buf[head], 5, maxWriteSize() + 2);
cirbuf.h
@@ -20,8 +20,8 @@ public: @@ -20,8 +20,8 @@ public:
20 CirBuf(size_t size); 20 CirBuf(size_t size);
21 ~CirBuf(); 21 ~CirBuf();
22 22
23 - int usedBytes() const;  
24 - int freeSpace() const; 23 + uint usedBytes() const;
  24 + uint freeSpace() const;
25 int maxWriteSize() const; 25 int maxWriteSize() const;
26 int maxReadSize() const; 26 int maxReadSize() const;
27 char *headPtr(); 27 char *headPtr();
client.cpp
@@ -8,24 +8,16 @@ @@ -8,24 +8,16 @@
8 Client::Client(int fd, ThreadData_p threadData) : 8 Client::Client(int fd, ThreadData_p threadData) :
9 fd(fd), 9 fd(fd),
10 readbuf(CLIENT_BUFFER_SIZE), 10 readbuf(CLIENT_BUFFER_SIZE),
  11 + writebuf(CLIENT_BUFFER_SIZE),
11 threadData(threadData) 12 threadData(threadData)
12 { 13 {
13 int flags = fcntl(fd, F_GETFL); 14 int flags = fcntl(fd, F_GETFL);
14 fcntl(fd, F_SETFL, flags | O_NONBLOCK); 15 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
15 - char *writebuf = (char*)malloc(CLIENT_BUFFER_SIZE);  
16 -  
17 - if (writebuf == NULL)  
18 - {  
19 - throw std::runtime_error("Malloc error constructing client.");  
20 - }  
21 -  
22 - this->writebuf = writebuf;  
23 } 16 }
24 17
25 Client::~Client() 18 Client::~Client()
26 { 19 {
27 close(fd); 20 close(fd);
28 - free(writebuf);  
29 } 21 }
30 22
31 // Do this from a place you'll know ownwership of the shared_ptr is being given up everywhere, so the close happens when the last owner gives it up. 23 // Do this from a place you'll know ownwership of the shared_ptr is being given up everywhere, so the close happens when the last owner gives it up.
@@ -89,25 +81,44 @@ void Client::writeMqttPacket(const MqttPacket &amp;packet) @@ -89,25 +81,44 @@ void Client::writeMqttPacket(const MqttPacket &amp;packet)
89 { 81 {
90 std::lock_guard<std::mutex> locker(writeBufMutex); 82 std::lock_guard<std::mutex> locker(writeBufMutex);
91 83
92 - if (packet.packetType == PacketType::PUBLISH && wwi > CLIENT_MAX_BUFFER_SIZE)  
93 - return;  
94 -  
95 - if (packet.getSizeIncludingNonPresentHeader() > getWriteBufMaxWriteSize())  
96 - growWriteBuffer(packet.getSizeIncludingNonPresentHeader()); 84 + if (packet.getSizeIncludingNonPresentHeader() > writebuf.freeSpace())
  85 + {
  86 + if (packet.packetType == PacketType::PUBLISH && writebuf.getSize() >= CLIENT_MAX_BUFFER_SIZE)
  87 + return;
  88 + writebuf.doubleSize();
  89 + }
97 90
98 if (!packet.containsFixedHeader()) 91 if (!packet.containsFixedHeader())
99 { 92 {
100 - writebuf[wwi++] = packet.getFirstByte(); 93 + writebuf.headPtr()[0] = packet.getFirstByte();
  94 + writebuf.advanceHead(1);
101 RemainingLength r = packet.getRemainingLength(); 95 RemainingLength r = packet.getRemainingLength();
102 - std::memcpy(&writebuf[wwi], r.bytes, r.len);  
103 - wwi += r.len;  
104 - }  
105 96
106 - std::memcpy(&writebuf[wwi], &packet.getBites()[0], packet.getBites().size());  
107 - wwi += packet.getBites().size(); 97 + ssize_t len_left = r.len;
  98 + int src_i = 0;
  99 + while (len_left > 0)
  100 + {
  101 + const size_t len = std::min<int>(len_left, writebuf.maxWriteSize());
  102 + std::memcpy(writebuf.headPtr(), &r.bytes[src_i], len);
  103 + writebuf.advanceHead(len);
  104 + src_i += len;
  105 + len_left -= len;
  106 + }
  107 + assert(len_left == 0);
  108 + assert(src_i == r.len);
  109 + }
108 110
109 - assert(wwi >= static_cast<int>(packet.getSizeIncludingNonPresentHeader()));  
110 - assert(wwi <= static_cast<int>(writeBufsize)); 111 + ssize_t len_left = packet.getBites().size();
  112 + int src_i = 0;
  113 + while (len_left > 0)
  114 + {
  115 + const size_t len = std::min<int>(len_left, writebuf.maxWriteSize());
  116 + std::memcpy(writebuf.headPtr(), &packet.getBites()[src_i], len);
  117 + writebuf.advanceHead(len);
  118 + src_i += len;
  119 + len_left -= len;
  120 + }
  121 + assert(len_left == 0);
111 122
112 if (packet.packetType == PacketType::DISCONNECT) 123 if (packet.packetType == PacketType::DISCONNECT)
113 setReadyForDisconnect(); 124 setReadyForDisconnect();
@@ -135,11 +146,13 @@ void Client::writePingResp() @@ -135,11 +146,13 @@ void Client::writePingResp()
135 146
136 std::cout << "Sending ping response to " << repr() << std::endl; 147 std::cout << "Sending ping response to " << repr() << std::endl;
137 148
138 - if (2 > getWriteBufMaxWriteSize())  
139 - growWriteBuffer(CLIENT_BUFFER_SIZE); 149 + if (2 > writebuf.freeSpace())
  150 + writebuf.doubleSize();
140 151
141 - writebuf[wwi++] = 0b11010000;  
142 - writebuf[wwi++] = 0; 152 + writebuf.headPtr()[0] = 0b11010000;
  153 + writebuf.advanceHead(1);
  154 + writebuf.headPtr()[0] = 0;
  155 + writebuf.advanceHead(1);
143 156
144 setReadyForWriting(true); 157 setReadyForWriting(true);
145 } 158 }
@@ -155,10 +168,10 @@ bool Client::writeBufIntoFd() @@ -155,10 +168,10 @@ bool Client::writeBufIntoFd()
155 return false; 168 return false;
156 169
157 int n; 170 int n;
158 - while ((n = write(fd, &writebuf[wri], getWriteBufBytesUsed())) != 0) 171 + while ((n = write(fd, writebuf.tailPtr(), writebuf.maxReadSize())) != 0)
159 { 172 {
160 if (n > 0) 173 if (n > 0)
161 - wri += n; 174 + writebuf.advanceTail(n);
162 if (n < 0) 175 if (n < 0)
163 { 176 {
164 if (errno == EINTR) 177 if (errno == EINTR)
@@ -170,13 +183,7 @@ bool Client::writeBufIntoFd() @@ -170,13 +183,7 @@ bool Client::writeBufIntoFd()
170 } 183 }
171 } 184 }
172 185
173 - if (wri == wwi)  
174 - {  
175 - wri = 0;  
176 - wwi = 0;  
177 -  
178 - setReadyForWriting(false);  
179 - } 186 + setReadyForWriting(writebuf.usedBytes() > 0);
180 187
181 return true; 188 return true;
182 } 189 }
@@ -189,24 +196,6 @@ std::string Client::repr() @@ -189,24 +196,6 @@ std::string Client::repr()
189 return a.str(); 196 return a.str();
190 } 197 }
191 198
192 -void Client::growWriteBuffer(size_t add_size)  
193 -{  
194 - if (add_size == 0)  
195 - return;  
196 -  
197 - const size_t grow_by = std::max<size_t>(add_size, writeBufsize*2);  
198 - const size_t newBufSize = writeBufsize + grow_by;  
199 - char *writebuf = (char*)realloc(this->writebuf, newBufSize);  
200 -  
201 - if (writebuf == NULL)  
202 - throw std::runtime_error("Memory allocation failure in growWriteBuffer()");  
203 -  
204 - this->writebuf = writebuf;  
205 - writeBufsize = newBufSize;  
206 -  
207 - std::cout << "New write buf size: " << writeBufsize << std::endl;  
208 -}  
209 -  
210 void Client::setReadyForWriting(bool val) 199 void Client::setReadyForWriting(bool val)
211 { 200 {
212 if (disconnecting) 201 if (disconnecting)
client.h
@@ -25,10 +25,7 @@ class Client @@ -25,10 +25,7 @@ class Client
25 25
26 CirBuf readbuf; 26 CirBuf readbuf;
27 27
28 - char *writebuf = NULL; // With many clients, it may not be smart to keep a (big) buffer around.  
29 - size_t writeBufsize = CLIENT_BUFFER_SIZE;  
30 - int wwi = 0;  
31 - int wri = 0; 28 + CirBuf writebuf;
32 29
33 bool authenticated = false; 30 bool authenticated = false;
34 bool connectPacketSeen = false; 31 bool connectPacketSeen = false;
@@ -50,21 +47,6 @@ class Client @@ -50,21 +47,6 @@ class Client
50 std::mutex writeBufMutex; 47 std::mutex writeBufMutex;
51 48
52 49
53 - size_t getWriteBufMaxWriteSize()  
54 - {  
55 - size_t available = writeBufsize - wwi;  
56 - return available;  
57 - }  
58 -  
59 - // Note: this is not the inverse of free space, because there can be non-used lead-in in the buffer!  
60 - size_t getWriteBufBytesUsed()  
61 - {  
62 - return wwi - wri;  
63 - };  
64 -  
65 - void growWriteBuffer(size_t add_size);  
66 -  
67 -  
68 void setReadyForWriting(bool val); 50 void setReadyForWriting(bool val);
69 void setReadyForReading(bool val); 51 void setReadyForReading(bool val);
70 52
@@ -90,7 +72,7 @@ public: @@ -90,7 +72,7 @@ public:
90 void writeMqttPacket(const MqttPacket &packet); 72 void writeMqttPacket(const MqttPacket &packet);
91 void writeMqttPacketAndBlameThisClient(const MqttPacket &packet); 73 void writeMqttPacketAndBlameThisClient(const MqttPacket &packet);
92 bool writeBufIntoFd(); 74 bool writeBufIntoFd();
93 - bool readyForDisconnecting() const { return disconnectWhenBytesWritten && wwi == wri && wwi == 0; } 75 + bool readyForDisconnecting() const { return disconnectWhenBytesWritten && writebuf.usedBytes() == 0; }
94 76
95 // Do this before calling an action that makes this client ready for writing, so that the EPOLLOUT will handle it. 77 // Do this before calling an action that makes this client ready for writing, so that the EPOLLOUT will handle it.
96 void setReadyForDisconnect() { disconnectWhenBytesWritten = true; } 78 void setReadyForDisconnect() { disconnectWhenBytesWritten = true; }