Line data Source code
1 : /*
2 : * (C) Copyright 2010 Marek Dopiera
3 : *
4 : * This file is part of CoherentDB.
5 : *
6 : * CoherentDB is free software: you can redistribute it and/or modify it
7 : * under the terms of the GNU General Public License as published by
8 : * the Free Software Foundation, either version 3 of the License, or
9 : * (at your option) any later version.
10 : *
11 : * CoherentDB is distributed in the hope that it will be useful, but
12 : * WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : * General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public
17 : * License along with CoherentDB. If not, see
18 : * http://www.gnu.org/licenses/.
19 : */
20 :
21 : #include <cstdlib>
22 : #include <exception>
23 : #include <cstring>
24 :
25 : #include <debug/asserts.h>
26 : #include <log/log.h>
27 : #include <util/multi_buffer.h>
28 :
29 : namespace coherent {
30 : namespace util {
31 :
32 : using namespace std;
33 : using namespace coherent::debug;
34 :
35 : #ifdef VALGRIND
36 : //it sometimes has some issues with memcpy - probably memcpy aligns what it
37 : //copies and valgrind doesn't like it
38 :
39 : void memcpy(char *dst, char const * src, size_t n)
40 : {
41 : for (size_t i = 0; i < n; ++i)
42 : *(dst++) = *(src++);
43 : }
44 : #endif
45 :
46 : //=========== buffer implementation ============================================
47 :
48 11976 : inline char * alloc_aligned(uint32_t size, uint32_t alignment)
49 : {
50 : char * mem;
51 11976 : if (alignment == buffer::NO_ALIGNMENT)
52 9380 : mem = reinterpret_cast<char*>(malloc(size));
53 : else
54 2596 : if (posix_memalign(reinterpret_cast<void**>(&mem), alignment, size))
55 0 : mem = 0;
56 11976 : if (mem == 0)
57 0 : throw bad_alloc();
58 11976 : return mem;
59 : }
60 :
61 11976 : buffer::buffer(uint32_t size, uint32_t alignment) :
62 11976 : data(alloc_aligned(size, alignment)),
63 11976 : size(size)
64 : {
65 11976 : }
66 :
67 11976 : buffer::~buffer()
68 : {
69 11976 : free(this->data);
70 11976 : }
71 :
72 : //=========== multi_buffer implementation ======================================
73 :
74 1128 : multi_buffer::multi_buffer(
75 : buffer_list & buffers,
76 : uint32_t size,
77 : uint32_t left_off
78 : ) :
79 : size(size),
80 1128 : left_off(left_off)
81 : {
82 1128 : buffers.swap(this->buffers);
83 : #ifndef NDEBUG
84 1128 : uint32_t real_size = 0;
85 17348 : for (
86 1128 : buffer_list::const_iterator i = this->buffers.begin();
87 8674 : i != this->buffers.end();
88 : ++i
89 : )
90 7546 : real_size += (*i)->get_size();
91 :
92 : d_assert(left_off + size <= real_size,
93 : "invalid use, left_off=" << left_off << ", size=" << size
94 : << ", real_size=" << real_size
95 : );
96 : #endif
97 :
98 : d_assert(
99 : this->buffers.empty()
100 : || this->buffers[0]->get_size() > left_off,
101 : "invalid use: buffer_size=" << this->buffers[0]->get_size() <<
102 : ", left_off=" << left_off
103 : );
104 : LOG(TRACE, "Created multi_buffer size=" << size << " off=" << left_off);
105 1128 : }
106 :
107 21 : multi_buffer::multi_buffer(multi_buffer const & o) :
108 : buffers(o.buffers),
109 : size(o.size),
110 21 : left_off(o.left_off)
111 : {
112 : LOG(TRACE, "Copied multi_buffer size=" << size << " off=" << left_off);
113 21 : }
114 :
115 : template<bool READ>
116 : void multi_buffer::do_rw(
117 : char * buf,
118 : uint32_t req_size,
119 : uint32_t req_off,
120 : uint32_t align
121 : )
122 : {
123 : d_assert(this->size >= req_size + req_off, "invalid use, req_size=" <<
124 : req_size << ", req_off=" << req_off << ", size=" << this->size
125 : );
126 :
127 : LOG(TRACE, "r/w to multi_buffer, size=" << req_size << ", off="
128 : << req_off
129 : );
130 :
131 5248 : if (!req_size)
132 23 : return; //perfectly legal situation
133 : d_assert(!this->buffers.empty(), "buffers list empty, req_size=" <<
134 : req_size << ", req_off=" << req_off
135 : );
136 :
137 5225 : uint32_t off = 0;
138 5225 : uint32_t size_left = req_size;
139 :
140 680345 : for (buffer_list::iterator it = this->buffers.begin(); size_left; ++it) {
141 : d_assert(it != this->buffers.end(), "too long request?");
142 : uint32_t const off_in_buf =
143 675097 : (it == this->buffers.begin()) ? this->left_off : 0;
144 675097 : uint32_t const buf_size = (*it)->get_size() - off_in_buf;
145 : d_assert(buf_size, "empty buffer? off=" << off);
146 675097 : if (off + buf_size > req_off) {
147 :
148 232913 : uint32_t const buf_start = (req_off > off) ? (req_off - off) : 0;
149 : d_assert(
150 : buf_size > buf_start,
151 : "how? buf_size=" << buf_size << ", buf_start=" << buf_start
152 : );
153 232913 : uint32_t const size = min(size_left, buf_size - buf_start);
154 : d_assert(off + buf_start >= req_off,
155 : "can't be, off=" << off << ", req_off=" << req_off
156 : );
157 232913 : uint32_t const out_off = off + buf_start - req_off;
158 : d_assert(
159 : out_off + size <= req_size,
160 : "trying to write past the buffer, out_off=" << out_off <<
161 : ", size=" << size << ", req_size=" << req_size
162 : );
163 : if (READ)
164 121309 : memcpy(
165 : buf + out_off,
166 : (*it)->get_data() + off_in_buf + buf_start,
167 : size
168 : );
169 : else {
170 111604 : if (!it->unique())
171 : {
172 : //ensure C-O-W
173 8840 : buffer_ptr new_buf(new buffer((*it)->get_size(), align));
174 4420 : memcpy(
175 : new_buf->get_data(),
176 : (*it)->get_data(),
177 : (*it)->get_size()
178 : );
179 4420 : *it = new_buf;
180 : }
181 111604 : memcpy(
182 : (*it)->get_data() + off_in_buf + buf_start,
183 : buf + out_off,
184 : size
185 : );
186 : }
187 : d_assert(size_left >= size, "mismatch, size_left=" << size_left <<
188 : ", size=" << size
189 : );
190 232913 : size_left -= size;
191 : }
192 675097 : off += buf_size;
193 : }
194 : }
195 :
196 : template
197 : void multi_buffer::do_rw<true>(
198 : char * buf,
199 : uint32_t size,
200 : uint32_t off,
201 : uint32_t align
202 : );
203 : template
204 : void multi_buffer::do_rw<false>(
205 : char * buf,
206 : uint32_t size,
207 : uint32_t off,
208 : uint32_t align
209 : );
210 :
211 : } // namespace util
212 9 : } // namespace coherent
213 :
|