| 249 | ThreadSafeTenant::~ThreadSafeTenant() {} |
| 250 | |
| 251 | ThreadSafeTransaction::ThreadSafeTransaction(DatabaseContext* cx, |
| 252 | ISingleThreadTransaction::Type type, |
| 253 | Optional<TenantName> tenant) |
| 254 | : tenantName(tenant), initialized(std::make_shared<std::atomic_bool>(false)) { |
| 255 | // Allocate memory for the transaction from this thread (so the pointer is known for subsequent method calls) |
| 256 | // but run its constructor on the main thread |
| 257 | |
| 258 | // It looks strange that the DatabaseContext::addref is deferred by the onMainThreadVoid call, but it is safe |
| 259 | // because the reference count of the DatabaseContext is solely managed from the main thread. If cx is destructed |
| 260 | // immediately after this call, it will defer the DatabaseContext::delref (and onMainThread preserves the order of |
| 261 | // these operations). |
| 262 | auto tr = this->tr = ISingleThreadTransaction::allocateOnForeignThread(type); |
| 263 | auto init = this->initialized; |
| 264 | // No deferred error -- if the construction of the RYW transaction fails, we have no where to put it |
| 265 | onMainThreadVoid([tr, cx, type, tenant, init]() { |
| 266 | cx->addref(); |
| 267 | if (tenant.present()) { |
| 268 | if (type == ISingleThreadTransaction::Type::RYW) { |
| 269 | new (tr) ReadYourWritesTransaction(Database(cx), tenant.get()); |
| 270 | } else { |
| 271 | tr->construct(Database(cx), tenant.get()); |
| 272 | } |
| 273 | } else { |
| 274 | if (type == ISingleThreadTransaction::Type::RYW) { |
| 275 | new (tr) ReadYourWritesTransaction(Database(cx)); |
| 276 | } else { |
| 277 | tr->construct(Database(cx)); |
| 278 | } |
| 279 | } |
| 280 | *init = true; |
| 281 | }); |
| 282 | } |
| 283 | |
| 284 | // This constructor is only used while refactoring fdbcli and only called from the main thread |
| 285 | ThreadSafeTransaction::ThreadSafeTransaction(ReadYourWritesTransaction* ryw) |