Changeset View
Changeset View
Standalone View
Standalone View
kdevplatform/language/duchain/topducontextdynamicdata.cpp
Show All 12 Lines | 1 | /* This is part of KDevelop | |||
---|---|---|---|---|---|
13 | Library General Public License for more details. | 13 | Library General Public License for more details. | ||
14 | 14 | | |||
15 | You should have received a copy of the GNU Library General Public License | 15 | You should have received a copy of the GNU Library General Public License | ||
16 | along with this library; see the file COPYING.LIB. If not, write to | 16 | along with this library; see the file COPYING.LIB. If not, write to | ||
17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 17 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
18 | Boston, MA 02110-1301, USA. | 18 | Boston, MA 02110-1301, USA. | ||
19 | */ | 19 | */ | ||
20 | 20 | | |||
21 | #include "topducontextdynamicdata_p.h" | ||||
21 | #include "topducontextdynamicdata.h" | 22 | #include "topducontextdynamicdata.h" | ||
22 | 23 | | |||
23 | #include <typeinfo> | 24 | #include <typeinfo> | ||
24 | #include <QFile> | 25 | #include <QFile> | ||
25 | #include <QByteArray> | 26 | #include <QByteArray> | ||
26 | 27 | | |||
27 | #include "declaration.h" | 28 | #include "declaration.h" | ||
28 | #include "declarationdata.h" | 29 | #include "declarationdata.h" | ||
29 | #include "ducontext.h" | 30 | #include "ducontext.h" | ||
30 | #include "topducontext.h" | 31 | #include "topducontext.h" | ||
31 | #include "topducontextdata.h" | 32 | #include "topducontextdata.h" | ||
32 | #include "ducontextdata.h" | 33 | #include "ducontextdata.h" | ||
33 | #include "ducontextdynamicdata.h" | 34 | #include "ducontextdynamicdata.h" | ||
34 | #include "duchainregister.h" | 35 | #include "duchainregister.h" | ||
35 | #include "serialization/itemrepository.h" | 36 | #include "serialization/itemrepository.h" | ||
36 | #include "problem.h" | 37 | #include "problem.h" | ||
37 | #include <debug.h> | 38 | #include <debug.h> | ||
38 | 39 | | |||
39 | //#define DEBUG_DATA_INFO | 40 | //#define DEBUG_DATA_INFO | ||
41 | #include <QElapsedTimer> | ||||
40 | 42 | | |||
41 | //This might be problematic on some systems, because really many mmaps are created | 43 | //This might be problematic on some systems, because really many mmaps are created | ||
44 | #if defined(KDEV_TOPCONTEXTS_USE_FILES) && !defined(KDEV_TOPCONTEXTS_DONT_MMAP) | ||||
42 | #define USE_MMAP | 45 | #define USE_MMAP | ||
46 | #endif | ||||
47 | | ||||
43 | using namespace KDevelop; | 48 | using namespace KDevelop; | ||
44 | 49 | | |||
45 | namespace { | 50 | namespace { | ||
46 | 51 | | |||
47 | /** | 52 | /** | ||
48 | * Serialize @p item into @p data and update @p totalDataOffset. | 53 | * Serialize @p item into @p data and update @p totalDataOffset. | ||
49 | * | 54 | * | ||
50 | * If @p isSharedDataItem is true, then the item's internal data pointer is not updated | 55 | * If @p isSharedDataItem is true, then the item's internal data pointer is not updated | ||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Line(s) | 154 | { | |||
151 | Q_UNUSED(data); | 156 | Q_UNUSED(data); | ||
152 | #ifdef DEBUG_DATA_INFO | 157 | #ifdef DEBUG_DATA_INFO | ||
153 | DUChainBaseData* item = (DUChainBaseData*)(pointerInData(data, info.dataOffset)); | 158 | DUChainBaseData* item = (DUChainBaseData*)(pointerInData(data, info.dataOffset)); | ||
154 | int size = DUChainItemSystem::self().dynamicSize(*item); | 159 | int size = DUChainItemSystem::self().dynamicSize(*item); | ||
155 | Q_ASSERT(size); | 160 | Q_ASSERT(size); | ||
156 | #endif | 161 | #endif | ||
157 | } | 162 | } | ||
158 | 163 | | |||
159 | QString basePath() | | |||
160 | { | | |||
161 | return globalItemRepositoryRegistry().path() + QLatin1String("/topcontexts/"); | | |||
162 | } | | |||
163 | | ||||
164 | QString pathForTopContext(const uint topContextIndex) | | |||
165 | { | | |||
166 | return basePath() + QString::number(topContextIndex); | | |||
167 | } | | |||
168 | | ||||
169 | enum LoadType { | 164 | enum LoadType { | ||
170 | PartialLoad, ///< Only load the direct member data | 165 | PartialLoad, ///< Only load the direct member data | ||
171 | FullLoad ///< Load everything, including appended lists | 166 | FullLoad ///< Load everything, including appended lists | ||
172 | }; | 167 | }; | ||
173 | template<typename F> | 168 | template<typename F> | ||
174 | void loadTopDUContextData(const uint topContextIndex, LoadType loadType, F callback) | 169 | void loadTopDUContextData(const uint topContextIndex, LoadType loadType, F callback) | ||
175 | { | 170 | { | ||
176 | QFile file(pathForTopContext(topContextIndex)); | 171 | TopDUContextStore store(topContextIndex); | ||
177 | if (!file.open(QIODevice::ReadOnly)) { | 172 | if (!store.open(QIODevice::ReadOnly)) { | ||
178 | return; | 173 | return; | ||
179 | } | 174 | } | ||
180 | 175 | | |||
181 | uint readValue; | 176 | uint readValue; | ||
182 | file.read((char*)&readValue, sizeof(uint)); | 177 | store.read((char*)&readValue, sizeof(uint)); | ||
183 | // now readValue is filled with the top-context data size | 178 | // now readValue is filled with the top-context data size | ||
184 | Q_ASSERT(readValue >= sizeof(TopDUContextData)); | 179 | Q_ASSERT(readValue >= sizeof(TopDUContextData)); | ||
185 | const QByteArray data = file.read(loadType == FullLoad ? readValue : sizeof(TopDUContextData)); | 180 | const QByteArray data = store.read(loadType == FullLoad ? readValue : sizeof(TopDUContextData)); | ||
186 | const TopDUContextData* topData = reinterpret_cast<const TopDUContextData*>(data.constData()); | 181 | const TopDUContextData* topData = reinterpret_cast<const TopDUContextData*>(data.constData()); | ||
187 | callback(topData); | 182 | callback(topData); | ||
188 | } | 183 | } | ||
189 | 184 | | |||
190 | template<typename T> | 185 | template<typename T> | ||
191 | struct PtrType; | 186 | struct PtrType; | ||
192 | 187 | | |||
193 | template<typename T> | 188 | template<typename T> | ||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Line(s) | 382 | if (realIndex < (uint)offsets.size() && offsets[realIndex].dataOffset) { | |||
388 | Q_ASSERT(!data->m_itemRetrievalForbidden); | 383 | Q_ASSERT(!data->m_itemRetrievalForbidden); | ||
389 | 384 | | |||
390 | //Construct the context, and eventuall its parent first | 385 | //Construct the context, and eventuall its parent first | ||
391 | ///TODO: ugly, remove need for const_cast | 386 | ///TODO: ugly, remove need for const_cast | ||
392 | auto itemData = const_cast<DUChainBaseData*>( | 387 | auto itemData = const_cast<DUChainBaseData*>( | ||
393 | reinterpret_cast<const DUChainBaseData*>(data->pointerInData(offsets[realIndex].dataOffset)) | 388 | reinterpret_cast<const DUChainBaseData*>(data->pointerInData(offsets[realIndex].dataOffset)) | ||
394 | ); | 389 | ); | ||
395 | 390 | | |||
391 | if (itemData) { | ||||
396 | auto& item = items[realIndex]; | 392 | auto& item = items[realIndex]; | ||
397 | item = dynamic_cast<typename PtrType<Item>::value>(DUChainItemSystem::self().create(itemData)); | 393 | item = dynamic_cast<typename PtrType<Item>::value>(DUChainItemSystem::self().create(itemData)); | ||
398 | if (!item) { | 394 | if (!item) { | ||
399 | //When this happens, the item has not been registered correctly. | 395 | //When this happens, the item has not been registered correctly. | ||
400 | //We can stop here, because else we will get crashes later. | 396 | //We can stop here, because else we will get crashes later. | ||
401 | qCritical() << "Failed to load item with identity" << itemData->classId; | 397 | qCritical() << "Failed to load item with identity" << itemData->classId; | ||
402 | return {}; | 398 | return {}; | ||
403 | } | 399 | } | ||
400 | } else { | ||||
401 | qCritical() << "Failed to load item at realIndex" << realIndex << "itemData=" << itemData; | ||||
402 | return {}; | ||||
403 | } | ||||
404 | 404 | | |||
405 | if (isSharedDataItem<Item>()) { | 405 | if (isSharedDataItem<Item>()) { | ||
406 | // NOTE: shared data must never point to mmapped data regions as otherwise we might end up with | 406 | // NOTE: shared data must never point to mmapped data regions as otherwise we might end up with | ||
407 | // use-after-free or double-deletions etc. pp. | 407 | // use-after-free or double-deletions etc. pp. | ||
408 | // thus, make the item always dynamic after deserialization | 408 | // thus, make the item always dynamic after deserialization | ||
409 | item->makeDynamic(); | 409 | item->makeDynamic(); | ||
410 | } | 410 | } | ||
411 | 411 | | |||
Show All 14 Lines | 425 | { | |||
426 | for (auto& item : items) { | 426 | for (auto& item : items) { | ||
427 | if (item) { | 427 | if (item) { | ||
428 | item->makeDynamic(); | 428 | item->makeDynamic(); | ||
429 | } | 429 | } | ||
430 | } | 430 | } | ||
431 | } | 431 | } | ||
432 | 432 | | |||
433 | template<class Item> | 433 | template<class Item> | ||
434 | void TopDUContextDynamicData::DUChainItemStorage<Item>::loadData(QFile* file) const | 434 | void TopDUContextDynamicData::DUChainItemStorage<Item>::loadData(TopDUContextStore* store) const | ||
435 | { | 435 | { | ||
436 | Q_ASSERT(offsets.isEmpty()); | 436 | Q_ASSERT(offsets.isEmpty()); | ||
437 | Q_ASSERT(items.isEmpty()); | 437 | Q_ASSERT(items.isEmpty()); | ||
438 | 438 | | |||
439 | uint readValue; | 439 | uint readValue; | ||
440 | file->read((char*)&readValue, sizeof(uint)); | 440 | store->read((char*)&readValue, sizeof(uint)); | ||
441 | offsets.resize(readValue); | 441 | offsets.resize(readValue); | ||
442 | 442 | | |||
443 | file->read((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | 443 | store->read((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | ||
444 | 444 | | |||
445 | //Fill with zeroes for now, will be initialized on-demand | 445 | //Fill with zeroes for now, will be initialized on-demand | ||
446 | items.resize(offsets.size()); | 446 | items.resize(offsets.size()); | ||
447 | } | 447 | } | ||
448 | 448 | | |||
449 | template<class Item> | 449 | template<class Item> | ||
450 | void TopDUContextDynamicData::DUChainItemStorage<Item>::writeData(QFile* file) | 450 | void TopDUContextDynamicData::DUChainItemStorage<Item>::writeData(TopDUContextStore* store) | ||
451 | { | 451 | { | ||
452 | uint writeValue = offsets.size(); | 452 | uint writeValue = offsets.size(); | ||
453 | file->write((char*)&writeValue, sizeof(uint)); | 453 | store->write((char*)&writeValue, sizeof(uint)); | ||
454 | file->write((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | 454 | store->write((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | ||
455 | } | 455 | } | ||
456 | 456 | | |||
457 | //END DUChainItemStorage | 457 | //END DUChainItemStorage | ||
458 | 458 | | |||
459 | const char* TopDUContextDynamicData::pointerInData(uint totalOffset) const | 459 | const char* TopDUContextDynamicData::pointerInData(uint totalOffset) const | ||
460 | { | 460 | { | ||
461 | Q_ASSERT(!m_mappedData || m_data.isEmpty()); | 461 | Q_ASSERT(!m_mappedData || m_data.isEmpty()); | ||
462 | 462 | | |||
Show All 34 Lines | 496 | void KDevelop::TopDUContextDynamicData::unmap() { | |||
497 | delete m_mappedFile; | 497 | delete m_mappedFile; | ||
498 | m_mappedFile = nullptr; | 498 | m_mappedFile = nullptr; | ||
499 | m_mappedData = nullptr; | 499 | m_mappedData = nullptr; | ||
500 | m_mappedDataSize = 0; | 500 | m_mappedDataSize = 0; | ||
501 | } | 501 | } | ||
502 | 502 | | |||
503 | bool TopDUContextDynamicData::fileExists(uint topContextIndex) | 503 | bool TopDUContextDynamicData::fileExists(uint topContextIndex) | ||
504 | { | 504 | { | ||
505 | return QFile::exists(pathForTopContext(topContextIndex)); | 505 | return TopDUContextStore::exists(topContextIndex); | ||
506 | } | 506 | } | ||
507 | 507 | | |||
508 | QList<IndexedDUContext> TopDUContextDynamicData::loadImporters(uint topContextIndex) { | 508 | QList<IndexedDUContext> TopDUContextDynamicData::loadImporters(uint topContextIndex) { | ||
509 | QList<IndexedDUContext> ret; | 509 | QList<IndexedDUContext> ret; | ||
510 | loadTopDUContextData(topContextIndex, FullLoad, [&ret] (const TopDUContextData* topData) { | 510 | loadTopDUContextData(topContextIndex, FullLoad, [&ret] (const TopDUContextData* topData) { | ||
511 | ret.reserve(topData->m_importersSize()); | 511 | ret.reserve(topData->m_importersSize()); | ||
512 | FOREACH_FUNCTION(const IndexedDUContext& importer, topData->m_importers) | 512 | FOREACH_FUNCTION(const IndexedDUContext& importer, topData->m_importers) | ||
513 | ret << importer; | 513 | ret << importer; | ||
Show All 25 Lines | 537 | void TopDUContextDynamicData::loadData() const { | |||
539 | static QMutex mutex; | 539 | static QMutex mutex; | ||
540 | QMutexLocker lock(&mutex); | 540 | QMutexLocker lock(&mutex); | ||
541 | if(m_dataLoaded) | 541 | if(m_dataLoaded) | ||
542 | return; | 542 | return; | ||
543 | 543 | | |||
544 | Q_ASSERT(!m_dataLoaded); | 544 | Q_ASSERT(!m_dataLoaded); | ||
545 | Q_ASSERT(m_data.isEmpty()); | 545 | Q_ASSERT(m_data.isEmpty()); | ||
546 | 546 | | |||
547 | QFile* file = new QFile(pathForTopContext(m_topContext->ownIndex())); | 547 | TopDUContextStore* store = new TopDUContextStore(m_topContext->ownIndex()); | ||
548 | bool open = file->open(QIODevice::ReadOnly); | 548 | bool open = store->open(QIODevice::ReadOnly); | ||
549 | Q_UNUSED(open); | 549 | Q_UNUSED(open); | ||
550 | Q_ASSERT(open); | 550 | Q_ASSERT(open); | ||
551 | Q_ASSERT(file->size()); | 551 | Q_ASSERT(store->size()); | ||
552 | 552 | | |||
553 | //Skip the offsets, we're already read them | 553 | //Skip the offsets, we're already read them | ||
554 | //Skip top-context data | 554 | //Skip top-context data | ||
555 | uint readValue; | 555 | uint readValue; | ||
556 | file->read((char*)&readValue, sizeof(uint)); | 556 | store->read((char*)&readValue, sizeof(uint)); | ||
557 | file->seek(readValue + file->pos()); | 557 | store->seek(readValue + store->pos()); | ||
558 | 558 | | |||
559 | m_contexts.loadData(file); | 559 | m_contexts.loadData(store); | ||
560 | m_declarations.loadData(file); | 560 | m_declarations.loadData(store); | ||
561 | m_problems.loadData(file); | 561 | m_problems.loadData(store); | ||
562 | 562 | | |||
563 | #ifdef USE_MMAP | 563 | #ifdef USE_MMAP | ||
564 | 564 | | |||
565 | m_mappedData = file->map(file->pos(), file->size() - file->pos()); | 565 | m_mappedData = store->map(store->pos(), store->size() - store->pos()); | ||
566 | if(m_mappedData) { | 566 | if(m_mappedData) { | ||
567 | m_mappedFile = file; | 567 | m_mappedFile = store; | ||
568 | m_mappedDataSize = file->size() - file->pos(); | 568 | m_mappedDataSize = store->size() - store->pos(); | ||
569 | file->close(); //Close the file, so there is less open file descriptors(May be problematic) | 569 | store->commit(); //Close the store, so there are less open file descriptors (May be problematic) | ||
570 | }else{ | 570 | }else{ | ||
571 | qCDebug(LANGUAGE) << "Failed to map" << file->fileName(); | 571 | qCDebug(LANGUAGE) << "Failed to map" << store->fileName(); | ||
572 | } | 572 | } | ||
573 | 573 | | |||
574 | #endif | 574 | #endif | ||
575 | 575 | | |||
576 | if(!m_mappedFile) { | 576 | if(!m_mappedFile) { | ||
577 | QByteArray data = file->readAll(); | 577 | QByteArray data = store->readAll(); | ||
578 | m_data.append({data, (uint)data.size()}); | 578 | m_data.append({data, (uint)data.size()}); | ||
579 | delete file; | 579 | delete store; | ||
580 | } | 580 | } | ||
581 | 581 | | |||
582 | m_dataLoaded = true; | 582 | m_dataLoaded = true; | ||
583 | } | 583 | } | ||
584 | 584 | | |||
585 | TopDUContext* TopDUContextDynamicData::load(uint topContextIndex) { | 585 | TopDUContext* TopDUContextDynamicData::load(uint topContextIndex) { | ||
586 | QFile file(pathForTopContext(topContextIndex)); | 586 | TopDUContextStore store(topContextIndex); | ||
587 | if(file.open(QIODevice::ReadOnly)) { | 587 | if(store.open(QIODevice::ReadOnly)) { | ||
588 | if(file.size() == 0) { | 588 | if(store.size() == 0) { | ||
589 | qCWarning(LANGUAGE) << "Top-context file is empty" << file.fileName(); | 589 | qCWarning(LANGUAGE) << "Top-context store is empty" << store.fileName(); | ||
590 | return nullptr; | 590 | return nullptr; | ||
591 | } | 591 | } | ||
592 | 592 | | |||
593 | uint readValue; | 593 | uint readValue; | ||
594 | file.read((char*)&readValue, sizeof(uint)); | 594 | store.read((char*)&readValue, sizeof(uint)); | ||
595 | //now readValue is filled with the top-context data size | 595 | //now readValue is filled with the top-context data size | ||
596 | QByteArray topContextData = file.read(readValue); | 596 | QByteArray topContextData = store.read(readValue); | ||
597 | 597 | | |||
598 | DUChainBaseData* topData = reinterpret_cast<DUChainBaseData*>(topContextData.data()); | 598 | DUChainBaseData* topData = reinterpret_cast<DUChainBaseData*>(topContextData.data()); | ||
599 | TopDUContext* ret = dynamic_cast<TopDUContext*>(DUChainItemSystem::self().create(topData)); | 599 | TopDUContext* ret = dynamic_cast<TopDUContext*>(DUChainItemSystem::self().create(topData)); | ||
600 | if(!ret) { | 600 | if(!ret) { | ||
601 | qCWarning(LANGUAGE) << "Cannot load a top-context from file" << file.fileName() << "- the required language-support for handling ID" << topData->classId << "is probably not loaded"; | 601 | qCWarning(LANGUAGE) << "Cannot load a top-context from store" << store.fileName() << "- the required language-support for handling ID" << topData->classId << "is probably not loaded"; | ||
602 | return nullptr; | 602 | return nullptr; | ||
603 | } | 603 | } | ||
604 | 604 | | |||
605 | TopDUContextDynamicData& target(*ret->m_dynamicData); | 605 | TopDUContextDynamicData& target(*ret->m_dynamicData); | ||
606 | 606 | | |||
607 | target.m_data.clear(); | 607 | target.m_data.clear(); | ||
608 | target.m_dataLoaded = false; | 608 | target.m_dataLoaded = false; | ||
609 | target.m_onDisk = true; | 609 | target.m_onDisk = true; | ||
Show All 20 Lines | 622 | void TopDUContextDynamicData::deleteOnDisk() { | |||
630 | m_contexts.deleteOnDisk(); | 630 | m_contexts.deleteOnDisk(); | ||
631 | m_declarations.deleteOnDisk(); | 631 | m_declarations.deleteOnDisk(); | ||
632 | m_problems.deleteOnDisk(); | 632 | m_problems.deleteOnDisk(); | ||
633 | 633 | | |||
634 | m_topContext->makeDynamic(); | 634 | m_topContext->makeDynamic(); | ||
635 | 635 | | |||
636 | m_onDisk = false; | 636 | m_onDisk = false; | ||
637 | 637 | | |||
638 | bool successfullyRemoved = QFile::remove(filePath()); | 638 | bool successfullyRemoved = TopDUContextStore::remove(m_topContext->ownIndex()); | ||
639 | Q_UNUSED(successfullyRemoved); | 639 | Q_UNUSED(successfullyRemoved); | ||
640 | Q_ASSERT(successfullyRemoved); | 640 | Q_ASSERT(successfullyRemoved); | ||
641 | qCDebug(LANGUAGE) << "deletion ready"; | 641 | qCDebug(LANGUAGE) << "deletion ready"; | ||
642 | } | 642 | } | ||
643 | 643 | | |||
644 | QString TopDUContextDynamicData::basePath() | ||||
645 | { | ||||
646 | return globalItemRepositoryRegistry().path() + QLatin1String("/topcontexts/"); | ||||
647 | } | ||||
648 | | ||||
649 | QString TopDUContextDynamicData::pathForTopContext(const uint topContextIndex) | ||||
650 | { | ||||
651 | return basePath() + QString::number(topContextIndex); | ||||
652 | } | ||||
653 | | ||||
644 | QString KDevelop::TopDUContextDynamicData::filePath() const { | 654 | QString KDevelop::TopDUContextDynamicData::filePath() const { | ||
645 | return pathForTopContext(m_topContext->ownIndex()); | 655 | return pathForTopContext(m_topContext->ownIndex()); | ||
646 | } | 656 | } | ||
647 | 657 | | |||
648 | bool TopDUContextDynamicData::hasChanged() const | 658 | bool TopDUContextDynamicData::hasChanged() const | ||
649 | { | 659 | { | ||
650 | return !m_onDisk || m_topContext->d_func()->m_dynamic | 660 | return !m_onDisk || m_topContext->d_func()->m_dynamic | ||
651 | || m_contexts.itemsHaveChanged() || m_declarations.itemsHaveChanged() | 661 | || m_contexts.itemsHaveChanged() || m_declarations.itemsHaveChanged() | ||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Line(s) | 720 | } | |||
713 | Q_ASSERT(actualTopContextDataSize == topContextDataSize); | 723 | Q_ASSERT(actualTopContextDataSize == topContextDataSize); | ||
714 | Q_ASSERT(m_topContextData.size() == 1); | 724 | Q_ASSERT(m_topContextData.size() == 1); | ||
715 | Q_ASSERT(!m_topContext->d_func()->isDynamic()); | 725 | Q_ASSERT(!m_topContext->d_func()->isDynamic()); | ||
716 | 726 | | |||
717 | unmap(); | 727 | unmap(); | ||
718 | 728 | | |||
719 | QDir().mkpath(basePath()); | 729 | QDir().mkpath(basePath()); | ||
720 | 730 | | |||
721 | QFile file(filePath()); | 731 | QElapsedTimer timer; | ||
722 | if(file.open(QIODevice::WriteOnly)) { | 732 | qint64 nBytes = 0; | ||
733 | if (Q_LIKELY(QFileInfo(basePath()).isWritable())) { | ||||
734 | timer.start(); | ||||
735 | TopDUContextStore store(m_topContext->ownIndex()); | ||||
736 | if(store.open(QIODevice::WriteOnly)) { | ||||
723 | 737 | | |||
724 | file.resize(0); | 738 | store.resize(0); | ||
725 | 739 | | |||
726 | file.write((char*)&topContextDataSize, sizeof(uint)); | 740 | store.write((char*)&topContextDataSize, sizeof(uint)); | ||
727 | foreach(const ArrayWithPosition& pos, m_topContextData) | 741 | foreach(const ArrayWithPosition& pos, m_topContextData) | ||
728 | file.write(pos.array.constData(), pos.position); | 742 | store.write(pos.array.constData(), pos.position); | ||
729 | 743 | | |||
730 | m_contexts.writeData(&file); | 744 | m_contexts.writeData(&store); | ||
731 | m_declarations.writeData(&file); | 745 | m_declarations.writeData(&store); | ||
732 | m_problems.writeData(&file); | 746 | m_problems.writeData(&store); | ||
733 | 747 | | |||
734 | foreach(const ArrayWithPosition& pos, m_data) | 748 | foreach(const ArrayWithPosition& pos, m_data) | ||
735 | file.write(pos.array.constData(), pos.position); | 749 | store.write(pos.array.constData(), pos.position); | ||
736 | 750 | | |||
737 | m_onDisk = true; | 751 | m_onDisk = true; | ||
738 | 752 | | |||
739 | if (file.size() == 0) { | 753 | nBytes = store.size(); | ||
754 | if (store.size() == 0) { | ||||
740 | qCWarning(LANGUAGE) << "Saving zero size top ducontext data"; | 755 | qCWarning(LANGUAGE) << "Saving zero size top ducontext data"; | ||
741 | } | 756 | } | ||
742 | file.close(); | 757 | store.commit(); | ||
743 | } else { | 758 | } else { | ||
744 | qCWarning(LANGUAGE) << "Cannot open top-context for writing"; | 759 | qCWarning(LANGUAGE) << "Cannot open topcontext" << store.fileName() << "for writing:" << store.errorString(); | ||
745 | } | 760 | } | ||
746 | // qCDebug(LANGUAGE) << "stored" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size(); | 761 | // qCDebug(LANGUAGE) << "stored" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size(); | ||
762 | } else { | ||||
763 | static bool warned = false; | ||||
764 | if (!warned) { | ||||
765 | qCWarning(LANGUAGE) << "Topcontexts directory" << basePath() << "is not writable, topcontext files won't be stored."; | ||||
766 | warned = true; | ||||
767 | } | ||||
768 | } | ||||
769 | if (timer.isValid()) { | ||||
770 | auto elapsed = timer.elapsed(); | ||||
771 | static quint64 totalBytes = 0; | ||||
772 | static double totalElapsed = 0.0; | ||||
773 | totalBytes += nBytes; | ||||
774 | totalElapsed += elapsed / 1000.0; | ||||
775 | if (totalBytes && totalElapsed >= 0.5) { | ||||
776 | qCInfo(LANGUAGE) << "Stored" << totalBytes << "topcontext bytes at" << totalBytes / totalElapsed << "bytes/second"; | ||||
777 | totalBytes = 0, totalElapsed = 0.0; | ||||
778 | } | ||||
779 | } | ||||
747 | } | 780 | } | ||
748 | 781 | | |||
749 | TopDUContextDynamicData::ItemDataInfo TopDUContextDynamicData::writeDataInfo(const ItemDataInfo& info, const DUChainBaseData* data, uint& totalDataOffset) { | 782 | TopDUContextDynamicData::ItemDataInfo TopDUContextDynamicData::writeDataInfo(const ItemDataInfo& info, const DUChainBaseData* data, uint& totalDataOffset) { | ||
750 | ItemDataInfo ret(info); | 783 | ItemDataInfo ret(info); | ||
751 | Q_ASSERT(info.dataOffset); | 784 | Q_ASSERT(info.dataOffset); | ||
752 | const auto size = DUChainItemSystem::self().dynamicSize(*data); | 785 | const auto size = DUChainItemSystem::self().dynamicSize(*data); | ||
753 | Q_ASSERT(size); | 786 | Q_ASSERT(size); | ||
754 | 787 | | |||
▲ Show 20 Lines • Show All 99 Lines • Show Last 20 Lines |