nsresult DOMStorageDBThread::PendingOperations::Execute(DOMStorageDBThread* aThread) { // Called outside the lock mozStorageTransaction transaction(aThread->mWorkerConnection, false); nsresult rv; for (uint32_t i = 0; i < mExecList.Length(); ++i) { DOMStorageDBThread::DBOperation* task = mExecList[i]; rv = task->Perform(aThread); if (NS_FAILED(rv)) { return rv; } } rv = transaction.Commit(); if (NS_FAILED(rv)) { return rv; } return NS_OK; }
void perform_keystate_export(int sockfd, engineconfig_type *config, const char *zone, int bds) { #define LOG_AND_RETURN(errmsg) do { ods_log_error_and_printf(\ sockfd,module_str,errmsg); return; } while (0) #define LOG_AND_RETURN_1(errmsg,param) do { ods_log_error_and_printf(\ sockfd,module_str,errmsg,param); return; } while (0) GOOGLE_PROTOBUF_VERIFY_VERSION; OrmConnRef conn; if (!ods_orm_connect(sockfd, config, conn)) return; // error already reported. { OrmTransactionRW transaction(conn); if (!transaction.started()) LOG_AND_RETURN("transaction not started"); std::string qzone; if (!OrmQuoteStringValue(conn, std::string(zone), qzone)) LOG_AND_RETURN("quoting string value failed"); { OrmResultRef rows; ::ods::keystate::EnforcerZone enfzone; if (!OrmMessageEnumWhere(conn,enfzone.descriptor(), rows,"name = %s",qzone.c_str())) LOG_AND_RETURN("zone enumeration failed"); if (!OrmFirst(rows)) { ods_printf(sockfd,"zone %s not found\n",zone); return; } OrmContextRef context; if (!OrmGetMessage(rows, enfzone, /*zones + keys*/true, context)) LOG_AND_RETURN("retrieving zone from database failed"); // we no longer need the query result, so release it. rows.release(); // Retrieve the dnskey ttl from the policy associated with the zone. ::ods::kasp::Policy policy; if (!load_kasp_policy(conn, enfzone.policy(), policy)) LOG_AND_RETURN_1("policy %s not found",enfzone.policy().c_str()); uint32_t dnskey_ttl = policy.keys().ttl(); bool bSubmitChanged = false; bool bRetractChanged = false; bool bKeytagChanged = false; for (int k=0; k<enfzone.keys_size(); ++k) { const ::ods::keystate::KeyData &key = enfzone.keys(k); if (key.role()==::ods::keystate::ZSK) continue; if (key.ds_at_parent()!=::ods::keystate::submit && key.ds_at_parent()!=::ods::keystate::submitted && key.ds_at_parent()!=::ods::keystate::retract && key.ds_at_parent()!=::ods::keystate::retracted ) continue; std::string dnskey; uint16_t keytag = dnskey_from_id(dnskey,key.locator().c_str(), key.role(), enfzone.name().c_str(), key.algorithm(),bds, dnskey_ttl); if (keytag) { ods_writen(sockfd, dnskey.c_str(), dnskey.size()); bSubmitChanged = key.ds_at_parent()==::ods::keystate::submit; bRetractChanged = key.ds_at_parent()==::ods::keystate::retract; bKeytagChanged = key.keytag()!=keytag; if (bSubmitChanged) { ::ods::keystate::KeyData *kd = enfzone.mutable_keys(k); kd->set_ds_at_parent(::ods::keystate::submitted); } if (bRetractChanged) { ::ods::keystate::KeyData *kd = enfzone.mutable_keys(k); kd->set_ds_at_parent(::ods::keystate::retracted); } if (bKeytagChanged) { ::ods::keystate::KeyData *kd = enfzone.mutable_keys(k); kd->set_keytag(keytag); } } else LOG_AND_RETURN_1("unable to find key with id %s", key.locator().c_str()); } if (bSubmitChanged || bRetractChanged || bKeytagChanged) { // Update the zone recursively in the database as keystates // have been changed because of the export if (!OrmMessageUpdate(context)) LOG_AND_RETURN("updating zone in the database failed"); if (!transaction.commit()) LOG_AND_RETURN("committing zone to the database failed"); } } } }
virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl) { const std::string ns = parseNsCollectionRequired(dbname, cmdObj); Status allowedWriteStatus = userAllowedWriteNS(ns); if (!allowedWriteStatus.isOK()) { return appendCommandStatus(result, allowedWriteStatus); } const BSONObj query = cmdObj.getObjectField("query"); const BSONObj fields = cmdObj.getObjectField("fields"); const BSONObj update = cmdObj.getObjectField("update"); const BSONObj sort = cmdObj.getObjectField("sort"); bool upsert = cmdObj["upsert"].trueValue(); bool returnNew = cmdObj["new"].trueValue(); bool remove = cmdObj["remove"].trueValue(); if (remove) { if (upsert) { errmsg = "remove and upsert can't co-exist"; return false; } if (!update.isEmpty()) { errmsg = "remove and update can't co-exist"; return false; } if (returnNew) { errmsg = "remove and returnNew can't co-exist"; return false; } } else if (!cmdObj.hasField("update")) { errmsg = "need remove or update"; return false; } bool ok = false; MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { errmsg = ""; // We can always retry because we only ever modify one document ok = runImpl(txn, dbname, ns, query, fields, update, sort, upsert, returnNew, remove, result, errmsg); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "findAndModify", ns); if (!ok && errmsg == "no-collection") { // Take X lock so we can create collection, then re-run operation. ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock lk(txn->lockState(), dbname, MODE_X); Client::Context ctx(txn, ns, false /* don't check version */); if (!fromRepl && !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbname)) { return appendCommandStatus(result, Status(ErrorCodes::NotMaster, str::stream() << "Not primary while creating collection " << ns << " during findAndModify")); } Database* db = ctx.db(); if (db->getCollection(ns)) { // someone else beat us to it, that's ok // we might race while we unlock if someone drops // but that's ok, we'll just do nothing and error out } else { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wuow(txn); uassertStatusOK(userCreateNS(txn, db, ns, BSONObj(), !fromRepl)); wuow.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "findAndModify", ns); } errmsg = ""; ok = runImpl(txn, dbname, ns, query, fields, update, sort, upsert, returnNew, remove, result, errmsg); }
void FlipCommand::onExecute(Context* context) { ContextWriter writer(context); Document* document = writer.document(); Sprite* sprite = writer.sprite(); { Transaction transaction(writer.context(), m_flipMask ? (m_flipType == doc::algorithm::FlipHorizontal ? "Flip Horizontal": "Flip Vertical"): (m_flipType == doc::algorithm::FlipHorizontal ? "Flip Canvas Horizontal": "Flip Canvas Vertical")); DocumentApi api = document->getApi(transaction); CelList cels; if (m_flipMask) { auto range = App::instance()->timeline()->range(); if (range.enabled()) cels = get_unique_cels(sprite, range); else if (writer.cel()) cels.push_back(writer.cel()); } else { for (Cel* cel : sprite->uniqueCels()) cels.push_back(cel); } Mask* mask = document->mask(); if (m_flipMask && document->isMaskVisible()) { Site site = *writer.site(); for (Cel* cel : cels) { site.frame(cel->frame()); site.layer(cel->layer()); int x, y; Image* image = site.image(&x, &y); if (!image) continue; // When the mask is inside the cel, we can try to flip the // pixels inside the image. if (cel->bounds().contains(mask->bounds())) { gfx::Rect flipBounds = mask->bounds(); flipBounds.offset(-x, -y); flipBounds &= image->bounds(); if (flipBounds.isEmpty()) continue; if (mask->bitmap() && !mask->isRectangular()) transaction.execute(new cmd::FlipMaskedCel(cel, m_flipType)); else api.flipImage(image, flipBounds, m_flipType); if (cel->layer()->isTransparent()) transaction.execute(new cmd::TrimCel(cel)); } // When the mask is bigger than the cel bounds, we have to // expand the cel, make the flip, and shrink it again. else { gfx::Rect flipBounds = (sprite->bounds() & mask->bounds()); if (flipBounds.isEmpty()) continue; ExpandCelCanvas expand( site, cel->layer(), TiledMode::NONE, transaction, ExpandCelCanvas::None); expand.validateDestCanvas(gfx::Region(flipBounds)); if (mask->bitmap() && !mask->isRectangular()) doc::algorithm::flip_image_with_mask( expand.getDestCanvas(), mask, m_flipType, document->bgColor(cel->layer())); else doc::algorithm::flip_image( expand.getDestCanvas(), flipBounds, m_flipType); expand.commit(); } } } else { for (Cel* cel : cels) { Image* image = cel->image(); api.setCelPosition (sprite, cel, (m_flipType == doc::algorithm::FlipHorizontal ? sprite->width() - image->width() - cel->x(): cel->x()), (m_flipType == doc::algorithm::FlipVertical ? sprite->height() - image->height() - cel->y(): cel->y())); api.flipImage(image, image->bounds(), m_flipType); } } // Flip the mask. Image* maskBitmap = mask->bitmap(); if (maskBitmap) { transaction.execute(new cmd::FlipMask(document, m_flipType)); // Flip the mask position because the if (!m_flipMask) transaction.execute( new cmd::SetMaskPosition( document, gfx::Point( (m_flipType == doc::algorithm::FlipHorizontal ? sprite->width() - mask->bounds().x2(): mask->bounds().x), (m_flipType == doc::algorithm::FlipVertical ? sprite->height() - mask->bounds().y2(): mask->bounds().y)))); document->generateMaskBoundaries(); } transaction.commit(); } update_screen_for_document(document); }
ExitCode _initAndListen(int listenPort) { Client::initThread("initandlisten"); _initWireSpec(); auto globalServiceContext = getGlobalServiceContext(); globalServiceContext->setFastClockSource(FastClockSourceFactory::create(Milliseconds(10))); globalServiceContext->setOpObserver(stdx::make_unique<OpObserver>()); DBDirectClientFactory::get(globalServiceContext) .registerImplementation([](OperationContext* txn) { return std::unique_ptr<DBClientBase>(new DBDirectClient(txn)); }); const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings(); { ProcessId pid = ProcessId::getCurrent(); LogstreamBuilder l = log(LogComponent::kControl); l << "MongoDB starting : pid=" << pid << " port=" << serverGlobalParams.port << " dbpath=" << storageGlobalParams.dbpath; if (replSettings.isMaster()) l << " master=" << replSettings.isMaster(); if (replSettings.isSlave()) l << " slave=" << (int)replSettings.isSlave(); const bool is32bit = sizeof(int*) == 4; l << (is32bit ? " 32" : " 64") << "-bit host=" << getHostNameCached() << endl; } DEV log(LogComponent::kControl) << "DEBUG build (which is slower)" << endl; #if defined(_WIN32) VersionInfoInterface::instance().logTargetMinOS(); #endif logProcessDetails(); checked_cast<ServiceContextMongoD*>(getGlobalServiceContext())->createLockFile(); transport::TransportLayerLegacy::Options options; options.port = listenPort; options.ipList = serverGlobalParams.bind_ip; auto sep = stdx::make_unique<ServiceEntryPointMongod>(getGlobalServiceContext()->getTransportLayer()); auto sepPtr = sep.get(); getGlobalServiceContext()->setServiceEntryPoint(std::move(sep)); // Create, start, and attach the TL auto transportLayer = stdx::make_unique<transport::TransportLayerLegacy>(options, sepPtr); auto res = transportLayer->setup(); if (!res.isOK()) { error() << "Failed to set up listener: " << res; return EXIT_NET_ERROR; } std::shared_ptr<DbWebServer> dbWebServer; if (serverGlobalParams.isHttpInterfaceEnabled) { dbWebServer.reset(new DbWebServer(serverGlobalParams.bind_ip, serverGlobalParams.port + 1000, getGlobalServiceContext(), new RestAdminAccess())); if (!dbWebServer->setupSockets()) { error() << "Failed to set up sockets for HTTP interface during startup."; return EXIT_NET_ERROR; } } getGlobalServiceContext()->initializeGlobalStorageEngine(); #ifdef MONGO_CONFIG_WIREDTIGER_ENABLED if (WiredTigerCustomizationHooks::get(getGlobalServiceContext())->restartRequired()) { exitCleanly(EXIT_CLEAN); } #endif // Warn if we detect configurations for multiple registered storage engines in // the same configuration file/environment. if (serverGlobalParams.parsedOpts.hasField("storage")) { BSONElement storageElement = serverGlobalParams.parsedOpts.getField("storage"); invariant(storageElement.isABSONObj()); BSONObj storageParamsObj = storageElement.Obj(); BSONObjIterator i = storageParamsObj.begin(); while (i.more()) { BSONElement e = i.next(); // Ignore if field name under "storage" matches current storage engine. if (storageGlobalParams.engine == e.fieldName()) { continue; } // Warn if field name matches non-active registered storage engine. if (getGlobalServiceContext()->isRegisteredStorageEngine(e.fieldName())) { warning() << "Detected configuration for non-active storage engine " << e.fieldName() << " when current storage engine is " << storageGlobalParams.engine; } } } if (!getGlobalServiceContext()->getGlobalStorageEngine()->getSnapshotManager()) { if (moe::startupOptionsParsed.count("replication.enableMajorityReadConcern") && moe::startupOptionsParsed["replication.enableMajorityReadConcern"].as<bool>()) { // Note: we are intentionally only erroring if the user explicitly requested that we // enable majority read concern. We do not error if the they are implicitly enabled for // CSRS because a required step in the upgrade procedure can involve an mmapv1 node in // the CSRS in the REMOVED state. This is handled by the TopologyCoordinator. invariant(replSettings.isMajorityReadConcernEnabled()); severe() << "Majority read concern requires a storage engine that supports" << " snapshots, such as wiredTiger. " << storageGlobalParams.engine << " does not support snapshots."; exitCleanly(EXIT_BADOPTIONS); } } logMongodStartupWarnings(storageGlobalParams, serverGlobalParams); { stringstream ss; ss << endl; ss << "*********************************************************************" << endl; ss << " ERROR: dbpath (" << storageGlobalParams.dbpath << ") does not exist." << endl; ss << " Create this directory or give existing directory in --dbpath." << endl; ss << " See http://dochub.mongodb.org/core/startingandstoppingmongo" << endl; ss << "*********************************************************************" << endl; uassert(10296, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.dbpath)); } { stringstream ss; ss << "repairpath (" << storageGlobalParams.repairpath << ") does not exist"; uassert(12590, ss.str().c_str(), boost::filesystem::exists(storageGlobalParams.repairpath)); } // TODO: This should go into a MONGO_INITIALIZER once we have figured out the correct // dependencies. if (snmpInit) { snmpInit(); } if (!storageGlobalParams.readOnly) { boost::filesystem::remove_all(storageGlobalParams.dbpath + "/_tmp/"); } if (mmapv1GlobalOptions.journalOptions & MMAPV1Options::JournalRecoverOnly) return EXIT_NET_ERROR; if (mongodGlobalParams.scriptingEnabled) { ScriptEngine::setup(); } auto startupOpCtx = getGlobalServiceContext()->makeOperationContext(&cc()); repairDatabasesAndCheckVersion(startupOpCtx.get()); if (storageGlobalParams.upgrade) { log() << "finished checking dbs"; exitCleanly(EXIT_CLEAN); } uassertStatusOK(getGlobalAuthorizationManager()->initialize(startupOpCtx.get())); /* this is for security on certain platforms (nonce generation) */ srand((unsigned)(curTimeMicros64() ^ startupSrandTimer.micros())); // The snapshot thread provides historical collection level and lock statistics for use // by the web interface. Only needed when HTTP is enabled. if (serverGlobalParams.isHttpInterfaceEnabled) { statsSnapshotThread.go(); invariant(dbWebServer); stdx::thread web(stdx::bind(&webServerListenThread, dbWebServer)); web.detach(); } #ifndef _WIN32 mongo::signalForkSuccess(); #endif AuthorizationManager* globalAuthzManager = getGlobalAuthorizationManager(); if (globalAuthzManager->shouldValidateAuthSchemaOnStartup()) { Status status = authindex::verifySystemIndexes(startupOpCtx.get()); if (!status.isOK()) { log() << redact(status); exitCleanly(EXIT_NEED_UPGRADE); } // SERVER-14090: Verify that auth schema version is schemaVersion26Final. int foundSchemaVersion; status = globalAuthzManager->getAuthorizationVersion(startupOpCtx.get(), &foundSchemaVersion); if (!status.isOK()) { log() << "Auth schema version is incompatible: " << "User and role management commands require auth data to have " << "at least schema version " << AuthorizationManager::schemaVersion26Final << " but startup could not verify schema version: " << status; exitCleanly(EXIT_NEED_UPGRADE); } if (foundSchemaVersion < AuthorizationManager::schemaVersion26Final) { log() << "Auth schema version is incompatible: " << "User and role management commands require auth data to have " << "at least schema version " << AuthorizationManager::schemaVersion26Final << " but found " << foundSchemaVersion << ". In order to upgrade " << "the auth schema, first downgrade MongoDB binaries to version " << "2.6 and then run the authSchemaUpgrade command."; exitCleanly(EXIT_NEED_UPGRADE); } } else if (globalAuthzManager->isAuthEnabled()) { error() << "Auth must be disabled when starting without auth schema validation"; exitCleanly(EXIT_BADOPTIONS); } else { // If authSchemaValidation is disabled and server is running without auth, // warn the user and continue startup without authSchema metadata checks. log() << startupWarningsLog; log() << "** WARNING: Startup auth schema validation checks are disabled for the " "database." << startupWarningsLog; log() << "** This mode should only be used to manually repair corrupted auth " "data." << startupWarningsLog; } auto shardingInitialized = uassertStatusOK(ShardingState::get(startupOpCtx.get()) ->initializeShardingAwarenessIfNeeded(startupOpCtx.get())); if (shardingInitialized) { reloadShardRegistryUntilSuccess(startupOpCtx.get()); } if (!storageGlobalParams.readOnly) { logStartup(startupOpCtx.get()); startFTDC(); getDeleter()->startWorkers(); restartInProgressIndexesFromLastShutdown(startupOpCtx.get()); if (serverGlobalParams.clusterRole == ClusterRole::ShardServer) { // Note: For replica sets, ShardingStateRecovery happens on transition to primary. if (!repl::getGlobalReplicationCoordinator()->isReplEnabled()) { uassertStatusOK(ShardingStateRecovery::recover(startupOpCtx.get())); } } else if (serverGlobalParams.clusterRole == ClusterRole::ConfigServer) { uassertStatusOK( initializeGlobalShardingStateForMongod(startupOpCtx.get(), ConnectionString::forLocal(), kDistLockProcessIdForConfigServer)); Balancer::create(startupOpCtx->getServiceContext()); } repl::getGlobalReplicationCoordinator()->startup(startupOpCtx.get()); const unsigned long long missingRepl = checkIfReplMissingFromCommandLine(startupOpCtx.get()); if (missingRepl) { log() << startupWarningsLog; log() << "** WARNING: mongod started without --replSet yet " << missingRepl << " documents are present in local.system.replset" << startupWarningsLog; log() << "** Restart with --replSet unless you are doing maintenance and " << " no other clients are connected." << startupWarningsLog; log() << "** The TTL collection monitor will not start because of this." << startupWarningsLog; log() << "** "; log() << " For more info see http://dochub.mongodb.org/core/ttlcollections"; log() << startupWarningsLog; } else { startTTLBackgroundJob(); } if (!replSettings.usingReplSets() && !replSettings.isSlave() && storageGlobalParams.engine != "devnull") { ScopedTransaction transaction(startupOpCtx.get(), MODE_X); Lock::GlobalWrite lk(startupOpCtx.get()->lockState()); FeatureCompatibilityVersion::setIfCleanStartup( startupOpCtx.get(), repl::StorageInterface::get(getGlobalServiceContext())); } } startClientCursorMonitor(); PeriodicTask::startRunningPeriodicTasks(); // MessageServer::run will return when exit code closes its socket and we don't need the // operation context anymore startupOpCtx.reset(); auto start = getGlobalServiceContext()->addAndStartTransportLayer(std::move(transportLayer)); if (!start.isOK()) { error() << "Failed to start the listener: " << start.toString(); return EXIT_NET_ERROR; } return waitForShutdown(); }
void KVStore::clear() { Transaction transaction(*this); mConn.exec("DELETE FROM data"); transaction.commit(); }
void Delete::execute() { if ( state() != Executing || !ok() ) return; if ( d->first ) { d->first = false; // We should really require DeleteMessages and Expunge only if // we know the mailbox isn't empty; but we'll know that inside // the transaction, and permitted() won't let us clean that up // if we don't have permission. So it'll have to wait until we // query permissions ourselves. requireRight( d->m, Permissions::DeleteMailbox ); requireRight( d->m, Permissions::DeleteMessages ); requireRight( d->m, Permissions::Expunge ); } if ( !permitted() ) return; if ( !transaction() ) { setTransaction( new Transaction( this ) ); Query * lock = new Query( "select * from mailboxes " "where id=$1 for update", 0 ); lock->bind( 1, d->m->id() ); transaction()->enqueue( lock ); d->messages = new Query( "select count(mm.uid)::bigint as messages " "from mailbox_messages mm " "join messages m on (mm.message=m.id) " "join mailboxes mb on (mm.mailbox=mb.id) " "where mm.mailbox=$1 and not mm.seen and " "(mm.uid>=mb.first_recent or m.idate>$2)", this ); d->messages->bind( 1, d->m->id() ); Date now; now.setCurrentTime(); d->messages->bind( 2, now.unixTime() - 20 ); transaction()->enqueue( d->messages ); transaction()->execute(); } if ( d->messages ) { if ( !d->messages->done() ) return; int64 messages = 0; Row * r = d->messages->nextRow(); if ( d->messages->failed() || !r ) error( No, "Could not determine if any messages exist" ); else messages = r->getBigint( "messages" ); if ( messages ) error( No, "Cannot delete mailbox: " + fn( messages ) + " messages exist" ); d->messages = 0; if ( ok() && d->m->remove( transaction() ) == 0 ) error( No, "Cannot delete mailbox " + d->m->name().ascii() ); Mailbox::refreshMailboxes( transaction() ); transaction()->commit(); } if ( !transaction()->done() ) return; if ( transaction()->failed() ) { error( No, "Database error: " + transaction()->error() ); return; } finish(); }
/// Opens a transaction. /// /// \return A new transaction. store::transaction store::backend::start(void) { return transaction(*this); }
IDBIndex* IDBObjectStore::createIndex(ScriptState* scriptState, const String& name, const IDBKeyPath& keyPath, const IDBIndexParameters& options, ExceptionState& exceptionState) { IDB_TRACE("IDBObjectStore::createIndex"); if (!m_transaction->isVersionChange()) { exceptionState.throwDOMException(InvalidStateError, IDBDatabase::notVersionChangeTransactionErrorMessage); return nullptr; } if (isDeleted()) { exceptionState.throwDOMException(InvalidStateError, IDBDatabase::objectStoreDeletedErrorMessage); return nullptr; } if (m_transaction->isFinished() || m_transaction->isFinishing()) { exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); return nullptr; } if (!m_transaction->isActive()) { exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); return nullptr; } if (!keyPath.isValid()) { exceptionState.throwDOMException(SyntaxError, "The keyPath argument contains an invalid key path."); return nullptr; } if (containsIndex(name)) { exceptionState.throwDOMException(ConstraintError, "An index with the specified name already exists."); return nullptr; } if (keyPath.type() == IDBKeyPath::ArrayType && options.multiEntry()) { exceptionState.throwDOMException(InvalidAccessError, "The keyPath argument was an array and the multiEntry option is true."); return nullptr; } if (!backendDB()) { exceptionState.throwDOMException(InvalidStateError, IDBDatabase::databaseClosedErrorMessage); return nullptr; } int64_t indexId = m_metadata.maxIndexId + 1; backendDB()->createIndex(m_transaction->id(), id(), indexId, name, keyPath, options.unique(), options.multiEntry()); ++m_metadata.maxIndexId; IDBIndexMetadata metadata(name, indexId, keyPath, options.unique(), options.multiEntry()); IDBIndex* index = IDBIndex::create(metadata, this, m_transaction.get()); m_indexMap.set(name, index); m_metadata.indexes.set(indexId, metadata); m_transaction->db()->indexCreated(id(), metadata); ASSERT(!exceptionState.hadException()); if (exceptionState.hadException()) return nullptr; IDBRequest* indexRequest = openCursor(scriptState, nullptr, WebIDBCursorDirectionNext, WebIDBTaskTypePreemptive); indexRequest->preventPropagation(); // This is kept alive by being the success handler of the request, which is in turn kept alive by the owning transaction. RefPtrWillBeRawPtr<IndexPopulator> indexPopulator = IndexPopulator::create(scriptState, transaction()->db(), m_transaction->id(), id(), metadata); indexRequest->setOnsuccess(indexPopulator); return index; }
RefPtr<IDBTransaction> LegacyDatabase::transaction(ScriptExecutionContext* context, const String& storeName, const String& mode, ExceptionCode& ec) { RefPtr<DOMStringList> storeNames = DOMStringList::create(); storeNames->append(storeName); return transaction(context, storeNames, mode, ec); }
void reverse_frames(Doc* doc, const DocRange& range) { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader, 500); Transaction transaction(writer.context(), "Reverse Frames"); DocApi api = doc->getApi(transaction); Sprite* sprite = doc->sprite(); LayerList layers; frame_t frameBegin, frameEnd; bool moveFrames = false; bool swapCels = false; switch (range.type()) { case DocRange::kCels: frameBegin = range.firstFrame(); frameEnd = range.lastFrame(); layers = range.selectedLayers().toLayerList(); swapCels = true; break; case DocRange::kFrames: frameBegin = range.firstFrame(); frameEnd = range.lastFrame(); layers = sprite->allLayers(); moveFrames = true; break; case DocRange::kLayers: frameBegin = frame_t(0); frameEnd = sprite->totalFrames()-1; layers = range.selectedLayers().toLayerList(); swapCels = true; break; } if (moveFrames) { for (frame_t frameRev = frameEnd+1; frameRev > frameBegin; --frameRev) { api.moveFrame(sprite, frameBegin, frameRev, kDropBeforeFrame, kDontAdjustTags); } } else if (swapCels) { for (Layer* layer : layers) { if (!layer->isImage()) continue; for (frame_t frame = frameBegin, frameRev = frameEnd; frame != (frameBegin+frameEnd)/2+1; ++frame, --frameRev) { if (frame == frameRev) continue; LayerImage* imageLayer = static_cast<LayerImage*>(layer); api.swapCel(imageLayer, frame, frameRev); } } } transaction.setNewDocRange(range); transaction.commit(); }
static DocRange drop_range_op( Doc* doc, const Op op, const DocRange& from, DocRangePlace place, const TagsHandling tagsHandling, DocRange to) { // Convert "first child" operation into a insert after last child. LayerGroup* parent = nullptr; if (to.type() == DocRange::kLayers && !to.selectedLayers().empty()) { if (place == kDocRangeFirstChild && (*to.selectedLayers().begin())->isGroup()) { place = kDocRangeAfter; parent = static_cast<LayerGroup*>((*to.selectedLayers().begin())); to.clearRange(); to.startRange(parent->lastLayer(), -1, DocRange::kLayers); to.endRange(parent->lastLayer(), -1); } else { parent = (*to.selectedLayers().begin())->parent(); } // Check that we're not moving a group inside itself for (auto moveThis : from.selectedLayers()) { if (moveThis == parent || (moveThis->isGroup() && has_child(static_cast<LayerGroup*>(moveThis), parent))) return from; } } if (place != kDocRangeBefore && place != kDocRangeAfter) { ASSERT(false); throw std::invalid_argument("Invalid 'place' argument"); } Sprite* sprite = doc->sprite(); // Check noop/trivial/do nothing cases, i.e., move a range to the same place. // Also check invalid cases, like moving a Background layer. switch (from.type()) { case DocRange::kCels: if (from == to) return from; break; case DocRange::kFrames: if (op == Move) { // Simple cases with one continuos range of frames that are a // no-op. if ((from.selectedFrames().ranges() == 1) && ((to.firstFrame() >= from.firstFrame() && to.lastFrame() <= from.lastFrame()) || (place == kDocRangeBefore && to.firstFrame() == from.lastFrame()+1) || (place == kDocRangeAfter && to.lastFrame() == from.firstFrame()-1)) && // If there are tags, this might not be a no-op (sprite->frameTags().empty() || tagsHandling == kDontAdjustTags)) { return from; } } break; case DocRange::kLayers: if (op == Move) { SelectedLayers srcSelLayers = from.selectedLayers(); SelectedLayers dstSelLayers = to.selectedLayers(); LayerList srcLayers = srcSelLayers.toLayerList(); LayerList dstLayers = dstSelLayers.toLayerList(); ASSERT(!srcLayers.empty()); if (srcLayers.empty()) return from; // dstLayers can be nullptr when we insert the first child in // a group. // Check no-ops when we move layers at the same level (all // layers with the same parent), all adjacents, and which are // moved to the same place. if (!dstSelLayers.empty() && srcSelLayers.hasSameParent() && dstSelLayers.hasSameParent() && are_layers_adjacent(srcLayers) && are_layers_adjacent(dstLayers)) { for (Layer* srcLayer : srcLayers) if (dstSelLayers.contains(srcLayer)) return from; if ((place == kDocRangeBefore && dstLayers.front() == srcLayers.back()->getNext()) || (place == kDocRangeAfter && dstLayers.back() == srcLayers.front()->getPrevious())) return from; } // We cannot move the background for (Layer* layer : srcSelLayers) if (layer->isBackground()) throw std::runtime_error("The background layer cannot be moved"); } // Before background if (place == kDocRangeBefore) { for (Layer* background : to.selectedLayers()) { if (background && background->isBackground()) throw std::runtime_error("You cannot move or copy something below the background layer"); } } break; } const char* undoLabel = NULL; switch (op) { case Move: undoLabel = "Move Range"; break; case Copy: undoLabel = "Copy Range"; break; default: ASSERT(false); throw std::invalid_argument("Invalid 'op' argument"); } DocRange resultRange; { const app::Context* context = static_cast<app::Context*>(doc->context()); const ContextReader reader(context); ContextWriter writer(reader, 500); Transaction transaction(writer.context(), undoLabel, ModifyDocument); DocApi api = doc->getApi(transaction); // TODO Try to add the range with just one call to DocApi // methods, to avoid generating a lot of cmd::SetCelFrame (see // DocApi::setCelFramePosition() function). switch (from.type()) { case DocRange::kCels: { LayerList allLayers = sprite->allBrowsableLayers(); if (allLayers.empty()) break; LayerList srcLayers = from.selectedLayers().toLayerList(); LayerList dstLayers = to.selectedLayers().toLayerList(); if (srcLayers.empty() || dstLayers.empty()) throw std::invalid_argument("You need to specify a non-empty cels range"); if (find_layer_index(allLayers, srcLayers.front()) < find_layer_index(allLayers, dstLayers.front())) { std::reverse(srcLayers.begin(), srcLayers.end()); std::reverse(dstLayers.begin(), dstLayers.end()); } if (from.firstFrame() < to.firstFrame()) { auto srcFrames = from.selectedFrames().makeReverse(); auto dstFrames = to.selectedFrames().makeReverse(); move_or_copy_cels(api, op, srcLayers, dstLayers, srcFrames, dstFrames); } else { const auto& srcFrames = from.selectedFrames(); const auto& dstFrames = to.selectedFrames(); move_or_copy_cels(api, op, srcLayers, dstLayers, srcFrames, dstFrames); } resultRange = to; break; } case DocRange::kFrames: { frame_t dstFrame; if (place == kDocRangeBefore) dstFrame = to.firstFrame(); else dstFrame = to.lastFrame(); resultRange = move_or_copy_frames(api, op, sprite, from, dstFrame, place, tagsHandling); break; } case DocRange::kLayers: { LayerList allLayers = sprite->allBrowsableLayers(); if (allLayers.empty()) break; LayerList srcLayers = from.selectedLayers().toLayerList(); LayerList dstLayers = to.selectedLayers().toLayerList(); ASSERT(!srcLayers.empty()); switch (op) { case Move: if (place == kDocRangeBefore) { Layer* beforeThis = (!dstLayers.empty() ? dstLayers.front(): nullptr); Layer* afterThis = nullptr; for (Layer* srcLayer : srcLayers) { if (afterThis) api.restackLayerAfter(srcLayer, parent, afterThis); else api.restackLayerBefore(srcLayer, parent, beforeThis); afterThis = srcLayer; } } else if (place == kDocRangeAfter) { Layer* afterThis = (!dstLayers.empty() ? dstLayers.back(): nullptr); for (Layer* srcLayer : srcLayers) { api.restackLayerAfter(srcLayer, parent, afterThis); afterThis = srcLayer; } } // Same set of layers than the "from" range resultRange = from; break; case Copy: { if (place == kDocRangeBefore) { Layer* beforeThis = (!dstLayers.empty() ? dstLayers.front(): nullptr); for (Layer* srcLayer : srcLayers) { Layer* copiedLayer = api.duplicateLayerBefore( srcLayer, parent, beforeThis); resultRange.startRange(copiedLayer, -1, DocRange::kLayers); resultRange.endRange(copiedLayer, -1); } } else if (place == kDocRangeAfter) { std::reverse(srcLayers.begin(), srcLayers.end()); Layer* afterThis = (!dstLayers.empty() ? dstLayers.back(): nullptr); for (Layer* srcLayer : srcLayers) { Layer* copiedLayer = api.duplicateLayerAfter( srcLayer, parent, afterThis); resultRange.startRange(copiedLayer, -1, DocRange::kLayers); resultRange.endRange(copiedLayer, -1); } } break; } } break; } } if (resultRange.type() != DocRange::kNone) transaction.setNewDocRange(resultRange); transaction.commit(); } return resultRange; }
void StorageAreaSync::sync(bool clearItems, const HashMap<String, String>& items) { ASSERT(!isMainThread()); if (items.isEmpty() && !clearItems && !m_syncCloseDatabase) return; if (m_databaseOpenFailed) return; if (!m_database.isOpen() && m_syncCloseDatabase) { m_syncCloseDatabase = false; return; } if (!m_database.isOpen()) openDatabase(CreateIfNonExistent); if (!m_database.isOpen()) return; // Closing this db because it is about to be deleted by StorageTracker. // The delete will be cancelled if StorageAreaSync needs to reopen the db // to write new items created after the request to delete the db. if (m_syncCloseDatabase) { m_syncCloseDatabase = false; m_database.close(); return; } SQLiteTransactionInProgressAutoCounter transactionCounter; // If the clear flag is set, then we clear all items out before we write any new ones in. if (clearItems) { SQLiteStatement clear(m_database, "DELETE FROM ItemTable"); if (clear.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database"); return; } int result = clear.step(); if (result != SQLITE_DONE) { LOG_ERROR("Failed to clear all items in the local storage database - %i", result); return; } } SQLiteStatement insert(m_database, "INSERT INTO ItemTable VALUES (?, ?)"); if (insert.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database"); return; } SQLiteStatement remove(m_database, "DELETE FROM ItemTable WHERE key=?"); if (remove.prepare() != SQLITE_OK) { LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database"); return; } HashMap<String, String>::const_iterator end = items.end(); SQLiteTransaction transaction(m_database); transaction.begin(); for (HashMap<String, String>::const_iterator it = items.begin(); it != end; ++it) { // Based on the null-ness of the second argument, decide whether this is an insert or a delete. SQLiteStatement& query = it->value.isNull() ? remove : insert; query.bindText(1, it->key); // If the second argument is non-null, we're doing an insert, so bind it as the value. if (!it->value.isNull()) query.bindBlob(2, it->value); int result = query.step(); if (result != SQLITE_DONE) { LOG_ERROR("Failed to update item in the local storage database - %i", result); break; } query.reset(); } transaction.commit(); }
nsresult FileManager::Init(nsIFile* aDirectory, mozIStorageConnection* aConnection) { NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); mFileInfos.Init(); bool exists; nsresult rv = aDirectory->Exists(&exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { bool isDirectory; rv = aDirectory->IsDirectory(&isDirectory); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(isDirectory, NS_ERROR_FAILURE); } else { rv = aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755); NS_ENSURE_SUCCESS(rv, rv); } mozStorageTransaction transaction(aConnection, false); rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE VIRTUAL TABLE fs USING filesystem;" )); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageStatement> stmt; rv = aConnection->CreateStatement(NS_LITERAL_CSTRING( "SELECT name, (name IN (SELECT id FROM file)) FROM fs " "WHERE path = :path" ), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); nsString path; rv = aDirectory->GetPath(path); NS_ENSURE_SUCCESS(rv, rv); rv = stmt->BindStringByName(NS_LITERAL_CSTRING("path"), path); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageServiceQuotaManagement> ss = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID); NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE); bool hasResult; while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) { nsString name; rv = stmt->GetString(0, name); NS_ENSURE_SUCCESS(rv, rv); PRInt32 flag = stmt->AsInt32(1); nsCOMPtr<nsIFile> file; rv = aDirectory->Clone(getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); rv = file->Append(name); NS_ENSURE_SUCCESS(rv, rv); if (flag) { rv = ss->UpdateQuotaInformationForFile(file); NS_ENSURE_SUCCESS(rv, rv); } else { rv = file->Remove(false); if (NS_FAILED(rv)) { NS_WARNING("Failed to remove orphaned file!"); } } } rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "DROP TABLE fs;" )); NS_ENSURE_SUCCESS(rv, rv); rv = aDirectory->GetPath(mDirectoryPath); NS_ENSURE_SUCCESS(rv, rv); transaction.Commit(); return NS_OK; }
bool AbstractDatabase::performOpenAndVerify(bool shouldSetVersionInNewDatabase, ExceptionCode& ec) { const int maxSqliteBusyWaitTime = 30000; if (!m_sqliteDatabase.open(m_filename, true)) { LOG_ERROR("Unable to open database at path %s", m_filename.ascii().data()); ec = INVALID_STATE_ERR; return false; } if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum()) LOG_ERROR("Unable to turn on incremental auto-vacuum for database %s", m_filename.ascii().data()); m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); String currentVersion; { MutexLocker locker(guidMutex()); GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid); if (entry != guidToVersionMap().end()) { // Map null string to empty string (see updateGuidVersionMap()). currentVersion = entry->second.isNull() ? String("") : entry->second.threadsafeCopy(); LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data()); #if PLATFORM(CHROMIUM) // Note: In multi-process browsers the cached value may be inaccurate, but // we cannot read the actual version from the database without potentially // inducing a form of deadlock, a busytimeout error when trying to // access the database. So we'll use the cached value if we're unable to read // the value from the database file without waiting. // FIXME: Add an async openDatabase method to the DatabaseAPI. const int noSqliteBusyWaitTime = 0; m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime); String versionFromDatabase; if (getVersionFromDatabase(versionFromDatabase, false)) { currentVersion = versionFromDatabase; updateGuidVersionMap(m_guid, currentVersion); } m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); #endif } else { LOG(StorageAPI, "No cached version for guid %i", m_guid); SQLiteTransaction transaction(m_sqliteDatabase); transaction.begin(); if (!transaction.inProgress()) { LOG_ERROR("Unable to begin transaction while opening %s", databaseDebugName().ascii().data()); ec = INVALID_STATE_ERR; m_sqliteDatabase.close(); return false; } String tableName(infoTableName); if (!m_sqliteDatabase.tableExists(tableName)) { m_new = true; if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) { LOG_ERROR("Unable to create table %s in database %s", infoTableName, databaseDebugName().ascii().data()); ec = INVALID_STATE_ERR; transaction.rollback(); m_sqliteDatabase.close(); return false; } } else if (!getVersionFromDatabase(currentVersion, false)) { LOG_ERROR("Failed to get current version from database %s", databaseDebugName().ascii().data()); ec = INVALID_STATE_ERR; transaction.rollback(); m_sqliteDatabase.close(); return false; } if (currentVersion.length()) { LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data()); } else if (!m_new || shouldSetVersionInNewDatabase) { LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data()); if (!setVersionInDatabase(m_expectedVersion, false)) { LOG_ERROR("Failed to set version %s in database %s", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data()); ec = INVALID_STATE_ERR; transaction.rollback(); m_sqliteDatabase.close(); return false; } currentVersion = m_expectedVersion; } updateGuidVersionMap(m_guid, currentVersion); transaction.commit(); } } if (currentVersion.isNull()) { LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data()); currentVersion = ""; } // If the expected version isn't the empty string, ensure that the current database version we have matches that version. Otherwise, set an exception. // If the expected version is the empty string, then we always return with whatever version of the database we have. if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) { LOG(StorageAPI, "page expects version %s from database %s, which actually has version name %s - openDatabase() call will fail", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data(), currentVersion.ascii().data()); ec = INVALID_STATE_ERR; m_sqliteDatabase.close(); return false; } ASSERT(m_databaseAuthorizer); m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer); m_opened = true; if (m_new && !shouldSetVersionInNewDatabase) m_expectedVersion = ""; // The caller provided a creationCallback which will set the expected version. return true; }
/* Create a new key with the specified number of bits (or retrieve it from a pre-generated keypool) */ bool HsmKeyFactoryPB::CreateNewKey(int bits, const std::string &repository, const std::string &policy, int algorithm, KeyRole role, HsmKey **ppKey) { #if 0 // perform retrieval and update of a hsm key inside a single transaction. OrmTransactionRW transaction(_conn); if (!transaction.started()) return false; #endif // Find keys that are available and match exactly with the given parameters. { OrmResultRef rows; if (!OrmMessageEnumWhere(_conn, ::ods::hsmkey::HsmKey::descriptor(), rows, "inception IS NULL")) return false; ::ods::hsmkey::HsmKey *pbkey = new ::ods::hsmkey::HsmKey; for (bool next=OrmFirst(rows); next; next=OrmNext(rows)) { OrmContextRef context; if (OrmGetMessage(rows, *pbkey, true, context)) { if (!pbkey->has_inception() && pbkey->bits() == bits && pbkey->repository() == repository && pbkey->policy() == policy && pbkey->algorithm() == algorithm && pbkey->role() == (::ods::hsmkey::keyrole)role ) { // found a candidate, so we no longer need the rows rows.release(); pbkey->set_inception(time_now()); HsmKeyPB pbkey_ref(pbkey); // Fixate unset attributes that returned their default value. // Otherwise when we list the keys those values will show // up as 'not set' if (!pbkey->has_policy()) pbkey_ref.setPolicy(policy); if (!pbkey->has_algorithm()) pbkey_ref.setAlgorithm(algorithm); if (!pbkey->has_role()) pbkey_ref.setKeyRole(role); pbkey = NULL; // We have modified the key and need to update it. if (!OrmMessageUpdate(context)) return false; #if 0 if (!transaction.commit()) return false; #endif std::pair<std::map<std::string,HsmKeyPB>::iterator,bool> ret; ret = _keys.insert(std::pair<std::string,HsmKeyPB>( pbkey_ref.locator(),pbkey_ref)); *ppKey = &ret.first->second; return true; } } } delete pbkey; } #if 0 // explicit rollback not strictly needed as it's the default action. // but we want to be sure to leave the transaction before we start calling // callbacks on our delegate. transaction.rollback(); #endif // We were not able to find any suitable key, give up. if (_delegate) _delegate->OnKeyShortage(bits,repository,policy,algorithm,role); return false; }
nsresult DOMStorageDBThread::InitDatabase() { Telemetry::AutoTimer<Telemetry::LOCALDOMSTORAGE_INIT_DATABASE_MS> timer; nsresult rv; // Here we are on the worker thread. This opens the worker connection. MOZ_ASSERT(!NS_IsMainThread()); rv = OpenDatabaseConnection(); NS_ENSURE_SUCCESS(rv, rv); rv = TryJournalMode(); NS_ENSURE_SUCCESS(rv, rv); // Create a read-only clone (void)mWorkerConnection->Clone(true, getter_AddRefs(mReaderConnection)); NS_ENSURE_TRUE(mReaderConnection, NS_ERROR_FAILURE); mozStorageTransaction transaction(mWorkerConnection, false); // Ensure Goanna 1.9.1 storage table rv = mWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TABLE IF NOT EXISTS webappsstore2 (" "scope TEXT, " "key TEXT, " "value TEXT, " "secure INTEGER, " "owner TEXT)")); NS_ENSURE_SUCCESS(rv, rv); rv = mWorkerConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index" " ON webappsstore2(scope, key)")); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageFunction> function1(new nsReverseStringSQLFunction()); NS_ENSURE_TRUE(function1, NS_ERROR_OUT_OF_MEMORY); rv = mWorkerConnection->CreateFunction(NS_LITERAL_CSTRING("REVERSESTRING"), 1, function1); NS_ENSURE_SUCCESS(rv, rv); bool exists; // Check if there is storage of Goanna 1.9.0 and if so, upgrade that storage // to actual webappsstore2 table and drop the obsolete table. First process // this newer table upgrade to priority potential duplicates from older // storage table. rv = mWorkerConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"), &exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { rv = mWorkerConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("INSERT OR IGNORE INTO " "webappsstore2(scope, key, value, secure, owner) " "SELECT REVERSESTRING(domain) || '.:', key, value, secure, owner " "FROM webappsstore")); NS_ENSURE_SUCCESS(rv, rv); rv = mWorkerConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE webappsstore")); NS_ENSURE_SUCCESS(rv, rv); } // Check if there is storage of Goanna 1.8 and if so, upgrade that storage // to actual webappsstore2 table and drop the obsolete table. Potential // duplicates will be ignored. rv = mWorkerConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"), &exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { rv = mWorkerConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("INSERT OR IGNORE INTO " "webappsstore2(scope, key, value, secure, owner) " "SELECT REVERSESTRING(domain) || '.:', key, value, secure, domain " "FROM moz_webappsstore")); NS_ENSURE_SUCCESS(rv, rv); rv = mWorkerConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore")); NS_ENSURE_SUCCESS(rv, rv); } rv = transaction.Commit(); NS_ENSURE_SUCCESS(rv, rv); // Database open and all initiation operation are done. Switching this flag // to true allow main thread to read directly from the database. // If we would allow this sooner, we would have opened a window where main thread // read might operate on a totaly broken and incosistent database. mDBReady = true; // List scopes having any stored data nsCOMPtr<mozIStorageStatement> stmt; rv = mWorkerConnection->CreateStatement(NS_LITERAL_CSTRING("SELECT DISTINCT scope FROM webappsstore2"), getter_AddRefs(stmt)); NS_ENSURE_SUCCESS(rv, rv); mozStorageStatementScoper scope(stmt); while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&exists)) && exists) { nsAutoCString foundScope; rv = stmt->GetUTF8String(0, foundScope); NS_ENSURE_SUCCESS(rv, rv); MonitorAutoLock monitor(mThreadObserver->GetMonitor()); mScopesHavingData.PutEntry(foundScope); } return NS_OK; }
nsresult nsDOMStoragePersistentDB::Init(const nsString& aDatabaseName) { nsresult rv; nsCOMPtr<nsIFile> storageFile; rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(storageFile)); NS_ENSURE_SUCCESS(rv, rv); rv = storageFile->Append(aDatabaseName); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageService> service; service = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection)); if (rv == NS_ERROR_FILE_CORRUPTED) { // delete the db and try opening again rv = storageFile->Remove(PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); rv = service->OpenDatabase(storageFile, getter_AddRefs(mConnection)); } NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "PRAGMA temp_store = MEMORY")); NS_ENSURE_SUCCESS(rv, rv); mozStorageTransaction transaction(mConnection, PR_FALSE); // Ensure Gecko 1.9.1 storage table rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TABLE IF NOT EXISTS webappsstore2 (" "scope TEXT, " "key TEXT, " "value TEXT, " "secure INTEGER, " "owner TEXT)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE UNIQUE INDEX IF NOT EXISTS scope_key_index" " ON webappsstore2(scope, key)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TEMPORARY TABLE webappsstore2_temp (" "scope TEXT, " "key TEXT, " "value TEXT, " "secure INTEGER, " "owner TEXT)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE UNIQUE INDEX scope_key_index_temp" " ON webappsstore2_temp(scope, key)")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TEMPORARY VIEW webappsstore2_view AS " "SELECT * FROM webappsstore2_temp " "UNION ALL " "SELECT * FROM webappsstore2 " "WHERE NOT EXISTS (" "SELECT scope, key FROM webappsstore2_temp " "WHERE scope = webappsstore2.scope AND key = webappsstore2.key)")); NS_ENSURE_SUCCESS(rv, rv); // carry deletion to both the temporary table and the disk table rv = mConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING( "CREATE TEMPORARY TRIGGER webappsstore2_view_delete_trigger " "INSTEAD OF DELETE ON webappsstore2_view " "BEGIN " "DELETE FROM webappsstore2_temp " "WHERE scope = OLD.scope AND key = OLD.key; " "DELETE FROM webappsstore2 " "WHERE scope = OLD.scope AND key = OLD.key; " "END")); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageFunction> function1(new nsReverseStringSQLFunction()); NS_ENSURE_TRUE(function1, NS_ERROR_OUT_OF_MEMORY); rv = mConnection->CreateFunction(NS_LITERAL_CSTRING("REVERSESTRING"), 1, function1); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<mozIStorageFunction> function2(new nsIsOfflineSQLFunction()); NS_ENSURE_TRUE(function2, NS_ERROR_OUT_OF_MEMORY); rv = mConnection->CreateFunction(NS_LITERAL_CSTRING("ISOFFLINE"), 1, function2); NS_ENSURE_SUCCESS(rv, rv); PRBool exists; // Check if there is storage of Gecko 1.9.0 and if so, upgrade that storage // to actual webappsstore2 table and drop the obsolete table. First process // this newer table upgrade to priority potential duplicates from older // storage table. rv = mConnection->TableExists(NS_LITERAL_CSTRING("webappsstore"), &exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { rv = mConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("INSERT OR IGNORE INTO " "webappsstore2(scope, key, value, secure, owner) " "SELECT REVERSESTRING(domain) || '.:', key, value, secure, owner " "FROM webappsstore")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE webappsstore")); NS_ENSURE_SUCCESS(rv, rv); } // Check if there is storage of Gecko 1.8 and if so, upgrade that storage // to actual webappsstore2 table and drop the obsolete table. Potential // duplicates will be ignored. rv = mConnection->TableExists(NS_LITERAL_CSTRING("moz_webappsstore"), &exists); NS_ENSURE_SUCCESS(rv, rv); if (exists) { rv = mConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("INSERT OR IGNORE INTO " "webappsstore2(scope, key, value, secure, owner) " "SELECT REVERSESTRING(domain) || '.:', key, value, secure, domain " "FROM moz_webappsstore")); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->ExecuteSimpleSQL( NS_LITERAL_CSTRING("DROP TABLE moz_webappsstore")); NS_ENSURE_SUCCESS(rv, rv); } // temporary - disk synchronization statements rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "INSERT INTO webappsstore2_temp" " SELECT * FROM webappsstore2" " WHERE scope = :scope AND NOT EXISTS (" "SELECT scope, key FROM webappsstore2_temp " "WHERE scope = webappsstore2.scope AND key = webappsstore2.key)"), getter_AddRefs(mCopyToTempTableStatement)); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "INSERT OR REPLACE INTO webappsstore2" " SELECT * FROM webappsstore2_temp" " WHERE scope = :scope;"), getter_AddRefs(mCopyBackToDiskStatement)); NS_ENSURE_SUCCESS(rv, rv); rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_temp" " WHERE scope = :scope;"), getter_AddRefs(mDeleteTemporaryTableStatement)); NS_ENSURE_SUCCESS(rv, rv); // retrieve all keys associated with a domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "SELECT key, value, secure FROM webappsstore2_temp " "WHERE scope = :scope"), getter_AddRefs(mGetAllKeysStatement)); NS_ENSURE_SUCCESS(rv, rv); // retrieve a value given a domain and a key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "SELECT value, secure FROM webappsstore2_temp " "WHERE scope = :scope " "AND key = :key"), getter_AddRefs(mGetKeyValueStatement)); NS_ENSURE_SUCCESS(rv, rv); // insert a new key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "INSERT OR REPLACE INTO " "webappsstore2_temp(scope, key, value, secure) " "VALUES (:scope, :key, :value, :secure)"), getter_AddRefs(mInsertKeyStatement)); NS_ENSURE_SUCCESS(rv, rv); // update the secure status of an existing key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "UPDATE webappsstore2_temp " "SET secure = :secure " "WHERE scope = :scope " "AND key = :key "), getter_AddRefs(mSetSecureStatement)); NS_ENSURE_SUCCESS(rv, rv); // remove a key rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view " "WHERE scope = :scope " "AND key = :key"), getter_AddRefs(mRemoveKeyStatement)); NS_ENSURE_SUCCESS(rv, rv); // remove keys owned by a specific domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view " "WHERE scope GLOB :scope"), getter_AddRefs(mRemoveOwnerStatement)); NS_ENSURE_SUCCESS(rv, rv); // remove keys belonging exactly only to a specific domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view " "WHERE scope = :scope"), getter_AddRefs(mRemoveStorageStatement)); NS_ENSURE_SUCCESS(rv, rv); // remove all keys rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "DELETE FROM webappsstore2_view"), getter_AddRefs(mRemoveAllStatement)); NS_ENSURE_SUCCESS(rv, rv); // check the usage for a given owner that is an offline-app allowed domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "SELECT SUM(LENGTH(key) + LENGTH(value)) " "FROM (" "SELECT key,value FROM webappsstore2_temp " "WHERE scope GLOB :scope " "UNION ALL " "SELECT key,value FROM webappsstore2 " "WHERE scope GLOB :scope " "AND NOT EXISTS (" "SELECT scope, key " "FROM webappsstore2_temp " "WHERE scope = webappsstore2.scope " "AND key = webappsstore2.key" ")" ")"), getter_AddRefs(mGetFullUsageStatement)); NS_ENSURE_SUCCESS(rv, rv); // check the usage for a given owner that is not an offline-app allowed domain rv = mConnection->CreateStatement(NS_LITERAL_CSTRING( "SELECT SUM(LENGTH(key) + LENGTH(value)) " "FROM (" "SELECT key, value FROM webappsstore2_temp " "WHERE scope GLOB :scope " "AND NOT ISOFFLINE(scope) " "UNION ALL " "SELECT key, value FROM webappsstore2 " "WHERE scope GLOB :scope " "AND NOT ISOFFLINE(scope) " "AND NOT EXISTS (" "SELECT scope, key " "FROM webappsstore2_temp " "WHERE scope = webappsstore2.scope " "AND key = webappsstore2.key" ")" ")"), getter_AddRefs(mGetOfflineExcludedUsageStatement)); NS_ENSURE_SUCCESS(rv, rv); rv = transaction.Commit(); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result, bool fromRepl = false ) { // --- parse NamespaceString ns( dbname, cmdObj[name].String() ); Status status = userAllowedWriteNS( ns ); if ( !status.isOK() ) return appendCommandStatus( result, status ); if ( cmdObj["indexes"].type() != Array ) { errmsg = "indexes has to be an array"; result.append( "cmdObj", cmdObj ); return false; } std::vector<BSONObj> specs; { BSONObjIterator i( cmdObj["indexes"].Obj() ); while ( i.more() ) { BSONElement e = i.next(); if ( e.type() != Object ) { errmsg = "everything in indexes has to be an Object"; result.append( "cmdObj", cmdObj ); return false; } specs.push_back( e.Obj() ); } } if ( specs.size() == 0 ) { errmsg = "no indexes to add"; return false; } // check specs for ( size_t i = 0; i < specs.size(); i++ ) { BSONObj spec = specs[i]; if ( spec["ns"].eoo() ) { spec = _addNsToSpec( ns, spec ); specs[i] = spec; } if ( spec["ns"].type() != String ) { errmsg = "spec has no ns"; result.append( "spec", spec ); return false; } if ( ns != spec["ns"].String() ) { errmsg = "namespace mismatch"; result.append( "spec", spec ); return false; } } // now we know we have to create index(es) // Note: createIndexes command does not currently respect shard versioning. ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X); if (!fromRepl && !repl::getGlobalReplicationCoordinator()->canAcceptWritesForDatabase(dbname)) { return appendCommandStatus(result, Status(ErrorCodes::NotMaster, str::stream() << "Not primary while creating indexes in " << ns.ns())); } Database* db = dbHolder().get(txn, ns.db()); if (!db) { db = dbHolder().openDb(txn, ns.db()); } Collection* collection = db->getCollection( ns.ns() ); result.appendBool( "createdCollectionAutomatically", collection == NULL ); if ( !collection ) { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wunit(txn); collection = db->createCollection( txn, ns.ns() ); invariant( collection ); if (!fromRepl) { getGlobalEnvironment()->getOpObserver()->onCreateCollection( txn, ns, CollectionOptions()); } wunit.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns()); }
void run() { /***** * Dbo tutorial section 3. A first session *****/ /* * Setup a session, would typically be done once at application startup. * * For testing, we'll be using Sqlite3's special :memory: database. You * can replace this with an actual filename for actual persistence. */ dbo::backend::Sqlite3 sqlite3(":memory:"); sqlite3.setProperty("show-queries", "true"); dbo::Session session; session.setConnection(sqlite3); session.mapClass<User>("user"); /* * Try to create the schema (will fail if already exists). */ session.createTables(); { dbo::Transaction transaction(session); User *user = new User(); user->name = "Joe"; user->password = "******"; user->role = User::Visitor; user->karma = 13; dbo::ptr<User> userPtr = session.add(user); } /***** * Dbo tutorial section 4. Querying objects *****/ { dbo::Transaction transaction(session); dbo::ptr<User> joe = session.find<User>().where("name = ?").bind("Joe"); std::cerr << "Joe has karma: " << joe->karma << std::endl; dbo::ptr<User> joe2 = session.query< dbo::ptr<User> > ("select u from user u").where("name = ?").bind("Joe"); } { dbo::Transaction transaction(session); typedef dbo::collection< dbo::ptr<User> > Users; Users users = session.find<User>(); std::cerr << "We have " << users.size() << " users:" << std::endl; for (Users::const_iterator i = users.begin(); i != users.end(); ++i) std::cerr << " user " << (*i)->name << " with karma of " << (*i)->karma << std::endl; } /***** * Dbo tutorial section 5. Updating objects *****/ { dbo::Transaction transaction(session); dbo::ptr<User> joe = session.find<User>().where("name = ?").bind("Joe"); joe.modify()->karma++; joe.modify()->password = "******"; } { dbo::Transaction transaction(session); dbo::ptr<User> joe = session.find<User>().where("name = ?").bind("Joe"); if (joe) joe.remove(); } { dbo::Transaction transaction(session); dbo::ptr<User> silly = session.add(new User()); silly.modify()->name = "Silly"; silly.remove(); } }
virtual bool run(OperationContext* txn, const string& dbname, BSONObj& cmdObj, int options, string& errmsg, BSONObjBuilder& result) { const NamespaceString ns(parseNs(dbname, cmdObj)); Status status = userAllowedWriteNS(ns); if (!status.isOK()) return appendCommandStatus(result, status); if (cmdObj["indexes"].type() != Array) { errmsg = "indexes has to be an array"; result.append("cmdObj", cmdObj); return false; } std::vector<BSONObj> specs; { BSONObjIterator i(cmdObj["indexes"].Obj()); while (i.more()) { BSONElement e = i.next(); if (e.type() != Object) { errmsg = "everything in indexes has to be an Object"; result.append("cmdObj", cmdObj); return false; } specs.push_back(e.Obj()); } } if (specs.size() == 0) { errmsg = "no indexes to add"; return false; } // check specs for (size_t i = 0; i < specs.size(); i++) { BSONObj spec = specs[i]; if (spec["ns"].eoo()) { spec = _addNsToSpec(ns, spec); specs[i] = spec; } if (spec["ns"].type() != String) { errmsg = "ns field must be a string"; result.append("spec", spec); return false; } std::string nsFromUser = spec["ns"].String(); if (nsFromUser.empty()) { errmsg = "ns field cannot be an empty string"; result.append("spec", spec); return false; } if (ns != nsFromUser) { errmsg = str::stream() << "value of ns field '" << nsFromUser << "' doesn't match namespace " << ns.ns(); result.append("spec", spec); return false; } } // now we know we have to create index(es) // Note: createIndexes command does not currently respect shard versioning. ScopedTransaction transaction(txn, MODE_IX); Lock::DBLock dbLock(txn->lockState(), ns.db(), MODE_X); if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) { return appendCommandStatus( result, Status(ErrorCodes::NotMaster, str::stream() << "Not primary while creating indexes in " << ns.ns())); } Database* db = dbHolder().get(txn, ns.db()); if (!db) { db = dbHolder().openDb(txn, ns.db()); } Collection* collection = db->getCollection(ns.ns()); if (collection) { result.appendBool("createdCollectionAutomatically", false); } else { MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wunit(txn); collection = db->createCollection(txn, ns.ns(), CollectionOptions()); invariant(collection); wunit.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns()); result.appendBool("createdCollectionAutomatically", true); } const int numIndexesBefore = collection->getIndexCatalog()->numIndexesTotal(txn); result.append("numIndexesBefore", numIndexesBefore); auto client = txn->getClient(); ScopeGuard lastOpSetterGuard = MakeObjGuard(repl::ReplClientInfo::forClient(client), &repl::ReplClientInfo::setLastOpToSystemLastOpTime, txn); MultiIndexBlock indexer(txn, collection); indexer.allowBackgroundBuilding(); indexer.allowInterruption(); const size_t origSpecsSize = specs.size(); indexer.removeExistingIndexes(&specs); if (specs.size() == 0) { result.append("numIndexesAfter", numIndexesBefore); result.append("note", "all indexes already exist"); return true; } if (specs.size() != origSpecsSize) { result.append("note", "index already exists"); } for (size_t i = 0; i < specs.size(); i++) { const BSONObj& spec = specs[i]; if (spec["unique"].trueValue()) { status = checkUniqueIndexConstraints(txn, ns.ns(), spec["key"].Obj()); if (!status.isOK()) { return appendCommandStatus(result, status); } } if (spec["v"].isNumber() && spec["v"].numberInt() == 0) { return appendCommandStatus( result, Status(ErrorCodes::CannotCreateIndex, str::stream() << "illegal index specification: " << spec << ". " << "The option v:0 cannot be passed explicitly")); } } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { uassertStatusOK(indexer.init(specs)); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns()); // If we're a background index, replace exclusive db lock with an intent lock, so that // other readers and writers can proceed during this phase. if (indexer.getBuildInBackground()) { txn->recoveryUnit()->abandonSnapshot(); dbLock.relockWithMode(MODE_IX); if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) { return appendCommandStatus( result, Status(ErrorCodes::NotMaster, str::stream() << "Not primary while creating background indexes in " << ns.ns())); } } try { Lock::CollectionLock colLock(txn->lockState(), ns.ns(), MODE_IX); uassertStatusOK(indexer.insertAllDocumentsInCollection()); } catch (const DBException& e) { invariant(e.getCode() != ErrorCodes::WriteConflict); // Must have exclusive DB lock before we clean up the index build via the // destructor of 'indexer'. if (indexer.getBuildInBackground()) { try { // This function cannot throw today, but we will preemptively prepare for // that day, to avoid data corruption due to lack of index cleanup. txn->recoveryUnit()->abandonSnapshot(); dbLock.relockWithMode(MODE_X); if (!repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)) { return appendCommandStatus( result, Status(ErrorCodes::NotMaster, str::stream() << "Not primary while creating background indexes in " << ns.ns() << ": cleaning up index build failure due to " << e.toString())); } } catch (...) { std::terminate(); } } throw; } // Need to return db lock back to exclusive, to complete the index build. if (indexer.getBuildInBackground()) { txn->recoveryUnit()->abandonSnapshot(); dbLock.relockWithMode(MODE_X); uassert(ErrorCodes::NotMaster, str::stream() << "Not primary while completing index build in " << dbname, repl::getGlobalReplicationCoordinator()->canAcceptWritesFor(ns)); Database* db = dbHolder().get(txn, ns.db()); uassert(28551, "database dropped during index build", db); uassert(28552, "collection dropped during index build", db->getCollection(ns.ns())); } MONGO_WRITE_CONFLICT_RETRY_LOOP_BEGIN { WriteUnitOfWork wunit(txn); indexer.commit(); for (size_t i = 0; i < specs.size(); i++) { std::string systemIndexes = ns.getSystemIndexesCollection(); getGlobalServiceContext()->getOpObserver()->onCreateIndex( txn, systemIndexes, specs[i]); } wunit.commit(); } MONGO_WRITE_CONFLICT_RETRY_LOOP_END(txn, "createIndexes", ns.ns()); result.append("numIndexesAfter", collection->getIndexCatalog()->numIndexesTotal(txn)); lastOpSetterGuard.Dismiss(); return true; }
void Database::scheduleTransaction() { ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller. RefPtr<SQLTransactionBackend> transaction; if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) transaction = m_transactionQueue.takeFirst(); if (transaction && databaseContext()->databaseThread()) { auto task = DatabaseTransactionTask::create(transaction); LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction()); m_transactionInProgress = true; databaseContext()->databaseThread()->scheduleTask(WTF::move(task)); } else m_transactionInProgress = false; }
void repairDatabasesAndCheckVersion(OperationContext* txn) { LOG(1) << "enter repairDatabases (to check pdfile version #)"; ScopedTransaction transaction(txn, MODE_X); Lock::GlobalWrite lk(txn->lockState()); vector<string> dbNames; StorageEngine* storageEngine = txn->getServiceContext()->getGlobalStorageEngine(); storageEngine->listDatabases(&dbNames); // Repair all databases first, so that we do not try to open them if they are in bad shape if (storageGlobalParams.repair) { invariant(!storageGlobalParams.readOnly); for (vector<string>::const_iterator i = dbNames.begin(); i != dbNames.end(); ++i) { const string dbName = *i; LOG(1) << " Repairing database: " << dbName; fassert(18506, repairDatabase(txn, storageEngine, dbName)); } } const repl::ReplSettings& replSettings = repl::getGlobalReplicationCoordinator()->getSettings(); // On replica set members we only clear temp collections on DBs other than "local" during // promotion to primary. On pure slaves, they are only cleared when the oplog tells them // to. The local DB is special because it is not replicated. See SERVER-10927 for more // details. const bool shouldClearNonLocalTmpCollections = !(checkIfReplMissingFromCommandLine(txn) || replSettings.usingReplSets() || replSettings.isSlave()); const bool shouldDoCleanupForSERVER23299 = isSubjectToSERVER23299(txn); for (vector<string>::const_iterator i = dbNames.begin(); i != dbNames.end(); ++i) { const string dbName = *i; LOG(1) << " Recovering database: " << dbName; Database* db = dbHolder().openDb(txn, dbName); invariant(db); // First thing after opening the database is to check for file compatibility, // otherwise we might crash if this is a deprecated format. auto status = db->getDatabaseCatalogEntry()->currentFilesCompatible(txn); if (!status.isOK()) { if (status.code() == ErrorCodes::CanRepairToDowngrade) { // Convert CanRepairToDowngrade statuses to MustUpgrade statuses to avoid logging a // potentially confusing and inaccurate message. // // TODO SERVER-24097: Log a message informing the user that they can start the // current version of mongod with --repair and then proceed with normal startup. status = {ErrorCodes::MustUpgrade, status.reason()}; } severe() << "Unable to start mongod due to an incompatibility with the data files and" " this version of mongod: " << redact(status); severe() << "Please consult our documentation when trying to downgrade to a previous" " major release"; quickExit(EXIT_NEED_UPGRADE); return; } // Check if admin.system.version contains an invalid featureCompatibilityVersion. // If a valid featureCompatibilityVersion is present, cache it as a server parameter. if (dbName == "admin") { if (Collection* versionColl = db->getCollection(FeatureCompatibilityVersion::kCollection)) { BSONObj featureCompatibilityVersion; if (Helpers::findOne(txn, versionColl, BSON("_id" << FeatureCompatibilityVersion::kParameterName), featureCompatibilityVersion)) { auto version = FeatureCompatibilityVersion::parse(featureCompatibilityVersion); if (!version.isOK()) { severe() << version.getStatus(); fassertFailedNoTrace(40283); } serverGlobalParams.featureCompatibilityVersion.store(version.getValue()); } } } // Major versions match, check indexes const string systemIndexes = db->name() + ".system.indexes"; Collection* coll = db->getCollection(systemIndexes); unique_ptr<PlanExecutor> exec( InternalPlanner::collectionScan(txn, systemIndexes, coll, PlanExecutor::YIELD_MANUAL)); BSONObj index; PlanExecutor::ExecState state; while (PlanExecutor::ADVANCED == (state = exec->getNext(&index, NULL))) { const BSONObj key = index.getObjectField("key"); const string plugin = IndexNames::findPluginName(key); if (db->getDatabaseCatalogEntry()->isOlderThan24(txn)) { if (IndexNames::existedBefore24(plugin)) { continue; } log() << "Index " << index << " claims to be of type '" << plugin << "', " << "which is either invalid or did not exist before v2.4. " << "See the upgrade section: " << "http://dochub.mongodb.org/core/upgrade-2.4" << startupWarningsLog; } const Status keyStatus = validateKeyPattern(key); if (!keyStatus.isOK()) { log() << "Problem with index " << index << ": " << redact(keyStatus) << " This index can still be used however it cannot be rebuilt." << " For more info see" << " http://dochub.mongodb.org/core/index-validation" << startupWarningsLog; } if (index["v"].isNumber() && index["v"].numberInt() == 0) { log() << "WARNING: The index: " << index << " was created with the deprecated" << " v:0 format. This format will not be supported in a future release." << startupWarningsLog; log() << "\t To fix this, you need to rebuild this index." << " For instructions, see http://dochub.mongodb.org/core/rebuild-v0-indexes" << startupWarningsLog; } } // Non-yielding collection scans from InternalPlanner will never error. invariant(PlanExecutor::IS_EOF == state); if (replSettings.usingReplSets()) { // We only care about the _id index if we are in a replset checkForIdIndexes(txn, db); // Ensure oplog is capped (mmap does not guarantee order of inserts on noncapped // collections) if (db->name() == "local") { checkForCappedOplog(txn, db); } } if (shouldDoCleanupForSERVER23299) { handleSERVER23299ForDb(txn, db); } if (!storageGlobalParams.readOnly && (shouldClearNonLocalTmpCollections || dbName == "local")) { db->clearTmpCollections(txn); } } LOG(1) << "done repairDatabases"; }
void LocalStorageDatabase::updateDatabaseWithChangedItems(const HashMap<String, String>& changedItems) { if (!m_database.isOpen()) openDatabase(CreateIfNonExistent); if (!m_database.isOpen()) return; if (m_shouldClearItems) { m_shouldClearItems = false; SQLiteStatement clearStatement(m_database, "DELETE FROM ItemTable"); if (clearStatement.prepare() != SQLResultOk) { LOG_ERROR("Failed to prepare clear statement - cannot write to local storage database"); return; } int result = clearStatement.step(); if (result != SQLResultDone) { LOG_ERROR("Failed to clear all items in the local storage database - %i", result); return; } } SQLiteStatement insertStatement(m_database, "INSERT INTO ItemTable VALUES (?, ?)"); if (insertStatement.prepare() != SQLResultOk) { LOG_ERROR("Failed to prepare insert statement - cannot write to local storage database"); return; } SQLiteStatement deleteStatement(m_database, "DELETE FROM ItemTable WHERE key=?"); if (deleteStatement.prepare() != SQLResultOk) { LOG_ERROR("Failed to prepare delete statement - cannot write to local storage database"); return; } SQLiteTransaction transaction(m_database); transaction.begin(); HashMap<String, String>::const_iterator it = changedItems.begin(); const HashMap<String, String>::const_iterator end = changedItems.end(); for (; it != end; ++it) { // A null value means that the key/value pair should be deleted. SQLiteStatement& statement = it->value.isNull() ? deleteStatement : insertStatement; statement.bindText(1, it->key); // If we're inserting a key/value pair, bind the value as well. if (!it->value.isNull()) statement.bindBlob(2, it->value); int result = statement.step(); if (result != SQLResultDone) { LOG_ERROR("Failed to update item in the local storage database - %i", result); break; } statement.reset(); } transaction.commit(); }
void KisTransactionTest::testUndoWithUnswitchedFrames() { KisSurrogateUndoAdapter undoAdapter; const QRect imageRect(0,0,100,100); const KoColorSpace * cs = KoColorSpaceRegistry::instance()->rgb8(); KisPaintDeviceSP dev = new KisPaintDevice(cs); TestUtil::TestingTimedDefaultBounds *bounds = new TestUtil::TestingTimedDefaultBounds(); dev->setDefaultBounds(bounds); KisRasterKeyframeChannel *channel = dev->createKeyframeChannel(KisKeyframeChannel::Content); QVERIFY(channel); KisPaintDeviceFramesInterface *i = dev->framesInterface(); QVERIFY(i); QCOMPARE(i->frames().size(), 1); dev->fill(QRect(10,10,20,20), KoColor(Qt::white, cs)); KIS_DUMP_DEVICE_2(dev, imageRect, "00_f0_w20", "dd"); QCOMPARE(dev->exactBounds(), QRect(10,10,20,20)); // add keyframe at position 10 channel->addKeyframe(10); // add keyframe at position 11 channel->addKeyframe(11); // add keyframe at position 12 channel->addKeyframe(12); KIS_DUMP_DEVICE_2(dev, imageRect, "01_f0_b20", "dd"); QCOMPARE(dev->exactBounds(), QRect(10,10,20,20)); { KisTransaction transaction(kundo2_noi18n("first_stroke"), dev, 0); dev->clear(); dev->fill(QRect(40,40,21,21), KoColor(Qt::red, cs)); transaction.commit(&undoAdapter); KIS_DUMP_DEVICE_2(dev, imageRect, "02_f0_b21_stroke", "dd"); QCOMPARE(dev->exactBounds(), QRect(40,40,21,21)); } // switch to frame 10 bounds->testingSetTime(10); KIS_DUMP_DEVICE_2(dev, imageRect, "03_f10_b0_switched", "dd"); QVERIFY(dev->exactBounds().isEmpty()); { KisTransaction transaction(kundo2_noi18n("second_stroke"), dev, 0); dev->fill(QRect(60,60,22,22), KoColor(Qt::green, cs)); transaction.commit(&undoAdapter); KIS_DUMP_DEVICE_2(dev, imageRect, "04_f10_b22_stroke", "dd"); QCOMPARE(dev->exactBounds(), QRect(60,60,22,22)); } undoAdapter.undo(); KIS_DUMP_DEVICE_2(dev, imageRect, "05_f10_b0_undone", "dd"); QVERIFY(dev->exactBounds().isEmpty()); bounds->testingSetTime(0); KIS_DUMP_DEVICE_2(dev, imageRect, "06_f0_b21_undone", "dd"); QCOMPARE(dev->exactBounds(), QRect(40,40,21,21)); bounds->testingSetTime(10); QVERIFY(dev->exactBounds().isEmpty()); undoAdapter.undo(); KIS_DUMP_DEVICE_2(dev, imageRect, "07_f10_b0_undone_x2", "dd"); QVERIFY(dev->exactBounds().isEmpty()); bounds->testingSetTime(0); KIS_DUMP_DEVICE_2(dev, imageRect, "08_f0_b20_undone_x2", "dd"); QCOMPARE(dev->exactBounds(), QRect(10,10,20,20)); { KisTransaction transaction(kundo2_noi18n("third_move"), dev, 0); dev->moveTo(17,17); transaction.commit(&undoAdapter); KIS_DUMP_DEVICE_2(dev, imageRect, "09_f0_o27_move", "dd"); QCOMPARE(dev->exactBounds(), QRect(27,27,20,20)); } bounds->testingSetTime(10); QVERIFY(dev->exactBounds().isEmpty()); undoAdapter.undo(); KIS_DUMP_DEVICE_2(dev, imageRect, "10_f10_b0_undone_x3", "dd"); QVERIFY(dev->exactBounds().isEmpty()); bounds->testingSetTime(0); KIS_DUMP_DEVICE_2(dev, imageRect, "11_f0_b20_undone_x3", "dd"); QCOMPARE(dev->exactBounds(), QRect(10,10,20,20)); }
TreeItem* TraktorFeature::importLibrary(QString file) { //Give thread a low priority QThread* thisThread = QThread::currentThread(); thisThread->setPriority(QThread::LowestPriority); //Invisible root item of Traktor's child model TreeItem* root = NULL; //Delete all table entries of Traktor feature ScopedTransaction transaction(m_database); clearTable("traktor_playlist_tracks"); clearTable("traktor_library"); clearTable("traktor_playlists"); transaction.commit(); transaction.transaction(); QSqlQuery query(m_database); query.prepare("INSERT INTO traktor_library (artist, title, album, year," "genre,comment,tracknumber,bpm, bitrate,duration, location," "rating,key) VALUES (:artist, :title, :album, :year,:genre," ":comment, :tracknumber,:bpm, :bitrate,:duration, :location," ":rating,:key)"); //Parse Trakor XML file using SAX (for performance) QFile traktor_file(file); if (!traktor_file.open(QIODevice::ReadOnly | QIODevice::Text)) { qDebug() << "Cannot open Traktor music collection"; return NULL; } QXmlStreamReader xml(&traktor_file); bool inCollectionTag = false; //TODO(XXX) is this still needed to parse the library correctly? bool inEntryTag = false; bool inPlaylistsTag = false; bool isRootFolderParsed = false; int nAudioFiles = 0; while (!xml.atEnd() && !m_cancelImport) { xml.readNext(); if (xml.isStartElement()) { if (xml.name() == "COLLECTION") { inCollectionTag = true; } // Each "ENTRY" tag in <COLLECTION> represents a track if (inCollectionTag && xml.name() == "ENTRY" ) { inEntryTag = true; //parse track parseTrack(xml, query); ++nAudioFiles; //increment number of files in the music collection } if (xml.name() == "PLAYLISTS") { inPlaylistsTag = true; } if (inPlaylistsTag && !isRootFolderParsed && xml.name() == "NODE") { QXmlStreamAttributes attr = xml.attributes(); QString nodetype = attr.value("TYPE").toString(); QString name = attr.value("NAME").toString(); if (nodetype == "FOLDER" && name == "$ROOT") { //process all playlists root = parsePlaylists(xml); isRootFolderParsed = true; } } } if (xml.isEndElement()) { if (xml.name() == "COLLECTION") { inCollectionTag = false; } if (xml.name() == "ENTRY" && inCollectionTag) { inEntryTag = false; } if (xml.name() == "PLAYLISTS" && inPlaylistsTag) { inPlaylistsTag = false; } } } if (xml.hasError()) { // do error handling qDebug() << "Cannot process Traktor music collection"; if (root) delete root; return NULL; } qDebug() << "Found: " << nAudioFiles << " audio files in Traktor"; //initialize TraktorTableModel transaction.commit(); return root; }
/////////////////////////////////////////////////////////////////////////////// /// \brief Saves a set of WindowSettings to a bed. /// /// \details The bed and Id that are saved to are determined by the id field /// of the WindowSettings object passed in. If the WindowSettings /// already exist in the bed, a new history index will be created. /// /// If there is a problem saving the WindowSettings, a warning will /// be emitted, and false will be returned. /// /// \param window_settings The WindowSettings to save. /// \return \c true if the WindowSettings were saved successfully. /// /// \ingroup loading bool saveWindowSettings(const WindowSettings& window_settings) { try { std::shared_ptr<bed::Bed> bed = bed::openWritable(window_settings.id.bed); if (!bed) throw std::runtime_error("Could not open bed for writing!"); bed::Db& db = bed->getDb(); bed::Transaction transaction(db, bed::Transaction::Immediate); int history_index = 0; if (db.getInt(BE_WND_WINDOW_SETTINGS_SQL_TABLE_EXISTS, 0) == 0) { db.exec(BE_WND_WINDOW_SETTINGS_SQL_CREATE_TABLE); } else { bed::Stmt latest(db, Id(BE_WND_WINDOW_SETTINGS_SQLID_LATEST_INDEX), BE_WND_WINDOW_SETTINGS_SQL_LATEST_INDEX); latest.bind(1, window_settings.id.asset.value()); if (latest.step()) history_index = latest.getInt(0); } bed::Stmt save(db, Id(BE_WND_WINDOW_SETTINGS_SQLID_SAVE), BE_WND_WINDOW_SETTINGS_SQL_SAVE); save.bind(1, window_settings.id.asset.value()); save.bind(2, history_index + 1); save.bind(3, static_cast<int>(window_settings.mode)); save.bind(4, window_settings.system_positioned); save.bind(5, window_settings.save_position_on_close); save.bind(6, window_settings.position.x); save.bind(7, window_settings.position.y); save.bind(8, window_settings.size.x); save.bind(9, window_settings.size.y); save.bind(10, window_settings.monitor_index); save.bind(11, window_settings.refresh_rate); save.bind(12, static_cast<int>(window_settings.v_sync)); save.bind(13, window_settings.msaa_level); save.bind(14, window_settings.red_bits); save.bind(15, window_settings.green_bits); save.bind(16, window_settings.blue_bits); save.bind(17, window_settings.alpha_bits); save.bind(18, window_settings.depth_bits); save.bind(19, window_settings.stencil_bits); save.bind(20, window_settings.srgb_capable); save.bind(21, window_settings.use_custom_gamma); save.bind(22, window_settings.custom_gamma); save.bind(23, window_settings.context_version_major); save.bind(24, window_settings.context_version_minor); save.bind(25, window_settings.forward_compatible_context ? 1 : 0); save.bind(26, window_settings.debug_context ? 1 : 0); save.bind(27, static_cast<int>(window_settings.context_profile_type)); save.step(); transaction.commit(); return true; } catch (const bed::Db::error& err) { BE_LOG(VWarning) << "Database error while saving window settings!" << BE_LOG_NL << " Bed: " << window_settings.id.bed << BE_LOG_NL << "WindowSettings ID: " << window_settings.id.asset << BE_LOG_NL << " Exception: " << err.what() << BE_LOG_NL << " SQL: " << err.sql() << BE_LOG_END; } catch (const std::runtime_error& err) { BE_LOG(VWarning) << "Exception while saving window settings!" << BE_LOG_NL << " Bed: " << window_settings.id.bed << BE_LOG_NL << "WindowSettings ID: " << window_settings.id.asset << BE_LOG_NL << " Exception: " << err.what() << BE_LOG_END; } return false; }
QSet<int> DirectoryDAO::relocateDirectory(const QString& oldFolder, const QString& newFolder) { // TODO(rryan): This method could use error reporting. It can fail in // mysterious ways for example if a track in the oldFolder also has a zombie // track location in newFolder then the replace query will fail because the // location column becomes non-unique. ScopedTransaction transaction(m_database); QSqlQuery query(m_database); query.prepare("UPDATE " % DIRECTORYDAO_TABLE % " SET " % DIRECTORYDAO_DIR % "=" ":newFolder WHERE " % DIRECTORYDAO_DIR % " = :oldFolder"); query.bindValue(":newFolder", newFolder); query.bindValue(":oldFolder", oldFolder); if (!query.exec()) { LOG_FAILED_QUERY(query) << "coud not relocate directory" << oldFolder << "to" << newFolder; return QSet<int>(); } FieldEscaper escaper(m_database); QString startsWithOldFolder = escaper.escapeString(escaper.escapeStringForLike(oldFolder % '/', '%') + '%'); // Also update information in the track_locations table. This is where mixxx // gets the location information for a track. query.prepare(QString("SELECT library.id, track_locations.id, track_locations.location " "FROM library INNER JOIN track_locations ON " "track_locations.id = library.location WHERE " "track_locations.location LIKE %1 ESCAPE '%'") .arg(startsWithOldFolder)); if (!query.exec()) { LOG_FAILED_QUERY(query) << "coud not relocate path of tracks"; return QSet<int>(); } QSet<int> ids; QList<int> loc_ids; QStringList old_locs; while (query.next()) { ids.insert(query.value(0).toInt()); loc_ids.append(query.value(1).toInt()); old_locs.append(query.value(2).toString()); } QString replacement("UPDATE track_locations SET location = :newloc " "WHERE id = :id"); query.prepare(replacement); for (int i = 0; i < loc_ids.size(); ++i) { QString newloc = old_locs.at(i); newloc.replace(0, oldFolder.size(), newFolder); query.bindValue("newloc", newloc); query.bindValue("id", loc_ids.at(i)); if (!query.exec()) { LOG_FAILED_QUERY(query) << "coud not relocate path of tracks"; return QSet<int>(); } } qDebug() << "Relocated tracks:" << ids.size(); transaction.commit(); return ids; }
void LibraryScanner::slotStartScan() { qDebug() << "LibraryScanner::slotStartScan"; QSet<QString> trackLocations = m_trackDao.getTrackLocations(); QHash<QString, int> directoryHashes = m_libraryHashDao.getDirectoryHashes(); QRegExp extensionFilter = QRegExp(SoundSourceProxy::supportedFileExtensionsRegex(), Qt::CaseInsensitive); QRegExp coverExtensionFilter = QRegExp(CoverArtUtils::supportedCoverArtExtensionsRegex(), Qt::CaseInsensitive); QStringList directoryBlacklist = ScannerUtil::getDirectoryBlacklist(); m_scannerGlobal = ScannerGlobalPointer( new ScannerGlobal(trackLocations, directoryHashes, extensionFilter, coverExtensionFilter, directoryBlacklist)); m_scannerGlobal->startTimer(); emit(scanStarted()); // Try to upgrade the library from 1.7 (XML) to 1.8+ (DB) if needed. If the // upgrade_filename already exists, then do not try to upgrade since we have // already done it. // TODO(XXX) SETTINGS_PATH may change in new Mixxx Versions. Here we need // the SETTINGS_PATH from Mixxx V <= 1.7 QString upgrade_filename = QDir::homePath().append("/").append(SETTINGS_PATH).append("DBUPGRADED"); qDebug() << "upgrade filename is " << upgrade_filename; QFile upgradefile(upgrade_filename); if (!upgradefile.exists()) { QTime t2; t2.start(); LegacyLibraryImporter libImport(m_trackDao, m_playlistDao); connect(&libImport, SIGNAL(progress(QString)), this, SIGNAL(progressLoading(QString))); ScopedTransaction transaction(m_database); libImport.import(); transaction.commit(); qDebug("Legacy importer took %d ms", t2.elapsed()); } // First, we're going to mark all the directories that we've previously // hashed as needing verification. As we search through the directory tree // when we rescan, we'll mark any directory that does still exist as // verified. m_libraryHashDao.invalidateAllDirectories(); // Mark all the tracks in the library as needing verification of their // existence. (ie. we want to check they're still on your hard drive where // we think they are) m_trackDao.invalidateTrackLocationsInLibrary(); qDebug() << "Recursively scanning library."; // Start scanning the library. This prepares insertion queries in TrackDAO // (must be called before calling addTracksAdd) and begins a transaction. m_trackDao.addTracksPrepare(); // Recursivly scan each directory in the directories table. QStringList dirs = m_directoryDao.getDirs(); // If there are no directories then we have nothing to do. Cleanup and // finish the scan immediately. if (dirs.isEmpty()) { slotFinishScan(); return; } // Queue up recursive scan tasks for every directory. When all tasks are // done, TaskWatcher will signal slotFinishScan. TaskWatcher* pWatcher = &m_scannerGlobal->getTaskWatcher(); connect(pWatcher, SIGNAL(allTasksDone()), this, SLOT(slotFinishScan())); foreach (const QString& dirPath, dirs) { // Acquire a security bookmark for this directory if we are in a // sandbox. For speed we avoid opening security bookmarks when recursive // scanning so that relies on having an open bookmark for the containing // directory. MDir dir(dirPath); queueTask(new RecursiveScanDirectoryTask(this, m_scannerGlobal, dir.dir(), dir.token())); }
void SetLoopSectionCommand::onExecute(Context* ctx) { doc::Document* doc = ctx->activeDocument(); if (!doc) return; doc::Sprite* sprite = doc->sprite(); doc::frame_t begin = m_begin; doc::frame_t end = m_end; bool on = false; switch (m_action) { case Action::Auto: { auto range = App::instance()->timeline()->range(); if (range.enabled() && (range.frames() > 1)) { begin = range.selectedFrames().firstFrame(); end = range.selectedFrames().lastFrame(); on = true; } else { on = false; } break; } case Action::On: on = true; break; case Action::Off: on = false; break; } doc::FrameTag* loopTag = get_loop_tag(sprite); if (on) { if (!loopTag) { loopTag = create_loop_tag(begin, end); ContextWriter writer(ctx); Transaction transaction(writer.context(), "Add Loop"); transaction.execute(new cmd::AddFrameTag(sprite, loopTag)); transaction.commit(); } else if (loopTag->fromFrame() != begin || loopTag->toFrame() != end) { ContextWriter writer(ctx); Transaction transaction(writer.context(), "Set Loop Range"); transaction.execute(new cmd::SetFrameTagRange(loopTag, begin, end)); transaction.commit(); } else { Command* cmd = CommandsModule::instance()->getCommandByName(CommandId::FrameTagProperties); ctx->executeCommand(cmd); } } else { if (loopTag) { ContextWriter writer(ctx); Transaction transaction(writer.context(), "Remove Loop"); transaction.execute(new cmd::RemoveFrameTag(sprite, loopTag)); transaction.commit(); } } App::instance()->timeline()->invalidate(); }