Mercurial > hg > orthanc-databases
comparison Framework/PostgreSQL/PostgreSQLLargeObject.cpp @ 248:7a4f9bcb0bc2
PostgreSQL: Support of range reads from the storage area
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 14 Apr 2021 09:46:44 +0200 |
parents | 3236894320d6 |
children | 16aac0287485 |
comparison
equal
deleted
inserted
replaced
247:e57a5313ffe5 | 248:7a4f9bcb0bc2 |
---|---|
78 lo_close(pg, fd); | 78 lo_close(pg, fd); |
79 } | 79 } |
80 | 80 |
81 | 81 |
82 PostgreSQLLargeObject::PostgreSQLLargeObject(PostgreSQLDatabase& database, | 82 PostgreSQLLargeObject::PostgreSQLLargeObject(PostgreSQLDatabase& database, |
83 const void* data, | |
84 size_t size) : | |
85 database_(database) | |
86 { | |
87 Create(); | |
88 Write(data, size); | |
89 } | |
90 | |
91 | |
92 PostgreSQLLargeObject::PostgreSQLLargeObject(PostgreSQLDatabase& database, | |
93 const std::string& s) : | 83 const std::string& s) : |
94 database_(database) | 84 database_(database) |
95 { | 85 { |
96 Create(); | 86 Create(); |
97 | 87 |
111 private: | 101 private: |
112 PostgreSQLDatabase& database_; | 102 PostgreSQLDatabase& database_; |
113 int fd_; | 103 int fd_; |
114 size_t size_; | 104 size_t size_; |
115 | 105 |
116 public: | 106 void ReadInternal(PGconn* pg, |
117 Reader(PostgreSQLDatabase& database, | 107 std::string& target) |
118 const std::string& oid) : | 108 { |
119 database_(database) | 109 for (size_t position = 0; position < target.size(); ) |
120 { | 110 { |
121 PGconn* pg = reinterpret_cast<PGconn*>(database.pg_); | 111 size_t remaining = target.size() - position; |
122 Oid id = boost::lexical_cast<Oid>(oid); | 112 |
123 | 113 int nbytes = lo_read(pg, fd_, &target[position], remaining); |
124 fd_ = lo_open(pg, id, INV_READ); | |
125 | |
126 if (fd_ < 0 || | |
127 lo_lseek(pg, fd_, 0, SEEK_END) < 0) | |
128 { | |
129 LOG(ERROR) << "PostgreSQL: No such large object in the database; " | |
130 << "Make sure you use a transaction"; | |
131 database.ThrowException(false); | |
132 } | |
133 | |
134 // Get the size of the large object | |
135 int size = lo_tell(pg, fd_); | |
136 if (size < 0) | |
137 { | |
138 database.ThrowException(true); | |
139 } | |
140 size_ = static_cast<size_t>(size); | |
141 | |
142 // Go to the first byte of the object | |
143 lo_lseek(pg, fd_, 0, SEEK_SET); | |
144 } | |
145 | |
146 ~Reader() | |
147 { | |
148 lo_close(reinterpret_cast<PGconn*>(database_.pg_), fd_); | |
149 } | |
150 | |
151 size_t GetSize() const | |
152 { | |
153 return size_; | |
154 } | |
155 | |
156 void Read(char* target) | |
157 { | |
158 for (size_t position = 0; position < size_; ) | |
159 { | |
160 size_t remaining = size_ - position; | |
161 | |
162 int nbytes = lo_read(reinterpret_cast<PGconn*>(database_.pg_), fd_, target + position, remaining); | |
163 if (nbytes < 0) | 114 if (nbytes < 0) |
164 { | 115 { |
165 LOG(ERROR) << "PostgreSQL: Unable to read the large object in the database"; | 116 LOG(ERROR) << "PostgreSQL: Unable to read the large object in the database"; |
166 database_.ThrowException(false); | 117 database_.ThrowException(false); |
167 } | 118 } |
168 | 119 |
169 position += static_cast<size_t>(nbytes); | 120 position += static_cast<size_t>(nbytes); |
170 } | 121 } |
171 } | 122 } |
123 | |
124 public: | |
125 Reader(PostgreSQLDatabase& database, | |
126 const std::string& oid) : | |
127 database_(database) | |
128 { | |
129 PGconn* pg = reinterpret_cast<PGconn*>(database.pg_); | |
130 Oid id = boost::lexical_cast<Oid>(oid); | |
131 | |
132 fd_ = lo_open(pg, id, INV_READ); | |
133 | |
134 if (fd_ < 0 || | |
135 lo_lseek(pg, fd_, 0, SEEK_END) < 0) | |
136 { | |
137 LOG(ERROR) << "PostgreSQL: No such large object in the database; " | |
138 << "Make sure you use a transaction"; | |
139 database.ThrowException(false); | |
140 } | |
141 | |
142 // Get the size of the large object | |
143 int size = lo_tell(pg, fd_); | |
144 if (size < 0) | |
145 { | |
146 database.ThrowException(true); | |
147 } | |
148 size_ = static_cast<size_t>(size); | |
149 } | |
150 | |
151 ~Reader() | |
152 { | |
153 lo_close(reinterpret_cast<PGconn*>(database_.pg_), fd_); | |
154 } | |
155 | |
156 size_t GetSize() const | |
157 { | |
158 return size_; | |
159 } | |
160 | |
161 void ReadWhole(std::string& target) | |
162 { | |
163 if (target.size() != size_) | |
164 { | |
165 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
166 } | |
167 | |
168 PGconn* pg = reinterpret_cast<PGconn*>(database_.pg_); | |
169 | |
170 // Go to the first byte of the object | |
171 lo_lseek(pg, fd_, 0, SEEK_SET); | |
172 | |
173 ReadInternal(pg, target); | |
174 } | |
175 | |
176 void ReadRange(std::string& target, | |
177 uint64_t start) | |
178 { | |
179 PGconn* pg = reinterpret_cast<PGconn*>(database_.pg_); | |
180 | |
181 // Go to the first byte of the object | |
182 lo_lseek(pg, fd_, start, SEEK_SET); | |
183 | |
184 ReadInternal(pg, target); | |
185 } | |
172 }; | 186 }; |
173 | 187 |
174 | 188 |
175 void PostgreSQLLargeObject::Read(std::string& target, | 189 void PostgreSQLLargeObject::ReadWhole(std::string& target, |
176 PostgreSQLDatabase& database, | 190 PostgreSQLDatabase& database, |
177 const std::string& oid) | 191 const std::string& oid) |
178 { | 192 { |
179 Reader reader(database, oid); | 193 Reader reader(database, oid); |
180 target.resize(reader.GetSize()); | 194 target.resize(reader.GetSize()); |
181 | 195 |
182 if (target.size() > 0) | 196 if (target.size() > 0) |
183 { | 197 { |
184 reader.Read(&target[0]); | 198 reader.ReadWhole(target); |
185 } | 199 } |
186 } | 200 } |
187 | 201 |
188 | 202 |
189 void PostgreSQLLargeObject::Read(void*& target, | 203 void PostgreSQLLargeObject::ReadRange(std::string& target, |
190 size_t& size, | 204 PostgreSQLDatabase& database, |
191 PostgreSQLDatabase& database, | 205 const std::string& oid, |
192 const std::string& oid) | 206 uint64_t start, |
207 size_t length) | |
193 { | 208 { |
194 Reader reader(database, oid); | 209 Reader reader(database, oid); |
195 size = reader.GetSize(); | 210 |
196 | 211 if (start >= reader.GetSize() || |
197 if (size == 0) | 212 start + length > reader.GetSize()) |
198 { | 213 { |
199 target = NULL; | 214 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRange); |
200 } | 215 } |
201 else | 216 |
202 { | 217 target.resize(length); |
203 target = malloc(size); | 218 |
204 if (target == NULL) | 219 if (target.size() > 0) |
205 { | 220 { |
206 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotEnoughMemory); | 221 reader.ReadRange(target, start); |
207 } | |
208 | |
209 reader.Read(reinterpret_cast<char*>(target)); | |
210 } | 222 } |
211 } | 223 } |
212 | 224 |
213 | 225 |
214 std::string PostgreSQLLargeObject::GetOid() const | 226 std::string PostgreSQLLargeObject::GetOid() const |