| 1194 | } |
| 1195 | |
| 1196 | Status DBImpl::Write(const WriteOptions& options, WriteBatch* updates) { |
| 1197 | Writer w(&mutex_); |
| 1198 | w.batch = updates; |
| 1199 | w.sync = options.sync; |
| 1200 | w.done = false; |
| 1201 | |
| 1202 | MutexLock l(&mutex_); |
| 1203 | writers_.push_back(&w); |
| 1204 | while (!w.done && &w != writers_.front()) { |
| 1205 | w.cv.Wait(); |
| 1206 | } |
| 1207 | if (w.done) { |
| 1208 | return w.status; |
| 1209 | } |
| 1210 | |
| 1211 | // May temporarily unlock and wait. |
| 1212 | Status status = MakeRoomForWrite(updates == nullptr); |
| 1213 | uint64_t last_sequence = versions_->LastSequence(); |
| 1214 | Writer* last_writer = &w; |
| 1215 | if (status.ok() && updates != nullptr) { // nullptr batch is for compactions |
| 1216 | WriteBatch* write_batch = BuildBatchGroup(&last_writer); |
| 1217 | WriteBatchInternal::SetSequence(write_batch, last_sequence + 1); |
| 1218 | last_sequence += WriteBatchInternal::Count(write_batch); |
| 1219 | |
| 1220 | // Add to log and apply to memtable. We can release the lock |
| 1221 | // during this phase since &w is currently responsible for logging |
| 1222 | // and protects against concurrent loggers and concurrent writes |
| 1223 | // into mem_. |
| 1224 | { |
| 1225 | mutex_.Unlock(); |
| 1226 | status = log_->AddRecord(WriteBatchInternal::Contents(write_batch)); |
| 1227 | bool sync_error = false; |
| 1228 | if (status.ok() && options.sync) { |
| 1229 | status = logfile_->Sync(); |
| 1230 | if (!status.ok()) { |
| 1231 | sync_error = true; |
| 1232 | } |
| 1233 | } |
| 1234 | if (status.ok()) { |
| 1235 | status = WriteBatchInternal::InsertInto(write_batch, mem_); |
| 1236 | } |
| 1237 | mutex_.Lock(); |
| 1238 | if (sync_error) { |
| 1239 | // The state of the log file is indeterminate: the log record we |
| 1240 | // just added may or may not show up when the DB is re-opened. |
| 1241 | // So we force the DB into a mode where all future writes fail. |
| 1242 | RecordBackgroundError(status); |
| 1243 | } |
| 1244 | } |
| 1245 | if (write_batch == tmp_batch_) tmp_batch_->Clear(); |
| 1246 | |
| 1247 | versions_->SetLastSequence(last_sequence); |
| 1248 | } |
| 1249 | |
| 1250 | while (true) { |
| 1251 | Writer* ready = writers_.front(); |
| 1252 | writers_.pop_front(); |
| 1253 | if (ready != &w) { |