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 93 Lines • ▼ Show 20 Line(s) | 147 | { | |||
144 | Q_UNUSED(data); | 149 | Q_UNUSED(data); | ||
145 | #ifdef DEBUG_DATA_INFO | 150 | #ifdef DEBUG_DATA_INFO | ||
146 | DUChainBaseData* item = (DUChainBaseData*)(pointerInData(data, info.dataOffset)); | 151 | DUChainBaseData* item = (DUChainBaseData*)(pointerInData(data, info.dataOffset)); | ||
147 | int size = DUChainItemSystem::self().dynamicSize(*item); | 152 | int size = DUChainItemSystem::self().dynamicSize(*item); | ||
148 | Q_ASSERT(size); | 153 | Q_ASSERT(size); | ||
149 | #endif | 154 | #endif | ||
150 | } | 155 | } | ||
151 | 156 | | |||
152 | QString basePath() | | |||
153 | { | | |||
154 | return globalItemRepositoryRegistry().path() + "/topcontexts/"; | | |||
155 | } | | |||
156 | | ||||
157 | QString pathForTopContext(const uint topContextIndex) | | |||
158 | { | | |||
159 | return basePath() + QString::number(topContextIndex); | | |||
160 | } | | |||
161 | | ||||
162 | enum LoadType { | 157 | enum LoadType { | ||
163 | PartialLoad, ///< Only load the direct member data | 158 | PartialLoad, ///< Only load the direct member data | ||
164 | FullLoad ///< Load everything, including appended lists | 159 | FullLoad ///< Load everything, including appended lists | ||
165 | }; | 160 | }; | ||
166 | template<typename F> | 161 | template<typename F> | ||
167 | void loadTopDUContextData(const uint topContextIndex, LoadType loadType, F callback) | 162 | void loadTopDUContextData(const uint topContextIndex, LoadType loadType, F callback) | ||
168 | { | 163 | { | ||
169 | QFile file(pathForTopContext(topContextIndex)); | 164 | TopDUContextStore store(topContextIndex); | ||
170 | if (!file.open(QIODevice::ReadOnly)) { | 165 | if (!store.open(QIODevice::ReadOnly)) { | ||
171 | return; | 166 | return; | ||
172 | } | 167 | } | ||
173 | 168 | | |||
174 | uint readValue; | 169 | uint readValue; | ||
175 | file.read((char*)&readValue, sizeof(uint)); | 170 | store.read((char*)&readValue, sizeof(uint)); | ||
176 | // now readValue is filled with the top-context data size | 171 | // now readValue is filled with the top-context data size | ||
177 | Q_ASSERT(readValue >= sizeof(TopDUContextData)); | 172 | Q_ASSERT(readValue >= sizeof(TopDUContextData)); | ||
178 | const QByteArray data = file.read(loadType == FullLoad ? readValue : sizeof(TopDUContextData)); | 173 | const QByteArray data = store.read(loadType == FullLoad ? readValue : sizeof(TopDUContextData)); | ||
179 | const TopDUContextData* topData = reinterpret_cast<const TopDUContextData*>(data.constData()); | 174 | const TopDUContextData* topData = reinterpret_cast<const TopDUContextData*>(data.constData()); | ||
180 | callback(topData); | 175 | callback(topData); | ||
181 | } | 176 | } | ||
182 | 177 | | |||
183 | template<typename T> | 178 | template<typename T> | ||
184 | struct PtrType; | 179 | struct PtrType; | ||
185 | 180 | | |||
186 | template<typename T> | 181 | template<typename T> | ||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Line(s) | 375 | if (realIndex < (uint)offsets.size() && offsets[realIndex].dataOffset) { | |||
381 | Q_ASSERT(!data->m_itemRetrievalForbidden); | 376 | Q_ASSERT(!data->m_itemRetrievalForbidden); | ||
382 | 377 | | |||
383 | //Construct the context, and eventuall its parent first | 378 | //Construct the context, and eventuall its parent first | ||
384 | ///TODO: ugly, remove need for const_cast | 379 | ///TODO: ugly, remove need for const_cast | ||
385 | auto itemData = const_cast<DUChainBaseData*>( | 380 | auto itemData = const_cast<DUChainBaseData*>( | ||
386 | reinterpret_cast<const DUChainBaseData*>(data->pointerInData(offsets[realIndex].dataOffset)) | 381 | reinterpret_cast<const DUChainBaseData*>(data->pointerInData(offsets[realIndex].dataOffset)) | ||
387 | ); | 382 | ); | ||
388 | 383 | | |||
384 | if (itemData) { | ||||
389 | auto& item = items[realIndex]; | 385 | auto& item = items[realIndex]; | ||
390 | item = dynamic_cast<typename PtrType<Item>::value>(DUChainItemSystem::self().create(itemData)); | 386 | item = dynamic_cast<typename PtrType<Item>::value>(DUChainItemSystem::self().create(itemData)); | ||
391 | if (!item) { | 387 | if (!item) { | ||
392 | //When this happens, the item has not been registered correctly. | 388 | //When this happens, the item has not been registered correctly. | ||
393 | //We can stop here, because else we will get crashes later. | 389 | //We can stop here, because else we will get crashes later. | ||
394 | qCritical() << "Failed to load item with identity" << itemData->classId; | 390 | qCritical() << "Failed to load item with identity" << itemData->classId; | ||
395 | return {}; | 391 | return {}; | ||
396 | } | 392 | } | ||
393 | } else { | ||||
394 | qCritical() << "Failed to load item at realIndex" << realIndex << "itemData=" << itemData; | ||||
395 | return {}; | ||||
396 | } | ||||
397 | 397 | | |||
398 | if (isSharedDataItem<Item>()) { | 398 | if (isSharedDataItem<Item>()) { | ||
399 | // NOTE: shared data must never point to mmapped data regions as otherwise we might end up with | 399 | // NOTE: shared data must never point to mmapped data regions as otherwise we might end up with | ||
400 | // use-after-free or double-deletions etc. pp. | 400 | // use-after-free or double-deletions etc. pp. | ||
401 | // thus, make the item always dynamic after deserialization | 401 | // thus, make the item always dynamic after deserialization | ||
402 | item->makeDynamic(); | 402 | item->makeDynamic(); | ||
403 | } | 403 | } | ||
404 | 404 | | |||
Show All 14 Lines | 418 | { | |||
419 | for (auto& item : items) { | 419 | for (auto& item : items) { | ||
420 | if (item) { | 420 | if (item) { | ||
421 | item->makeDynamic(); | 421 | item->makeDynamic(); | ||
422 | } | 422 | } | ||
423 | } | 423 | } | ||
424 | } | 424 | } | ||
425 | 425 | | |||
426 | template<class Item> | 426 | template<class Item> | ||
427 | void TopDUContextDynamicData::DUChainItemStorage<Item>::loadData(QFile* file) const | 427 | void TopDUContextDynamicData::DUChainItemStorage<Item>::loadData(TopDUContextStore* store) const | ||
428 | { | 428 | { | ||
429 | Q_ASSERT(offsets.isEmpty()); | 429 | Q_ASSERT(offsets.isEmpty()); | ||
430 | Q_ASSERT(items.isEmpty()); | 430 | Q_ASSERT(items.isEmpty()); | ||
431 | 431 | | |||
432 | uint readValue; | 432 | uint readValue; | ||
433 | file->read((char*)&readValue, sizeof(uint)); | 433 | store->read((char*)&readValue, sizeof(uint)); | ||
434 | offsets.resize(readValue); | 434 | offsets.resize(readValue); | ||
435 | 435 | | |||
436 | file->read((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | 436 | store->read((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | ||
437 | 437 | | |||
438 | //Fill with zeroes for now, will be initialized on-demand | 438 | //Fill with zeroes for now, will be initialized on-demand | ||
439 | items.resize(offsets.size()); | 439 | items.resize(offsets.size()); | ||
440 | } | 440 | } | ||
441 | 441 | | |||
442 | template<class Item> | 442 | template<class Item> | ||
443 | void TopDUContextDynamicData::DUChainItemStorage<Item>::writeData(QFile* file) | 443 | void TopDUContextDynamicData::DUChainItemStorage<Item>::writeData(TopDUContextStore* store) | ||
444 | { | 444 | { | ||
445 | uint writeValue = offsets.size(); | 445 | uint writeValue = offsets.size(); | ||
446 | file->write((char*)&writeValue, sizeof(uint)); | 446 | store->write((char*)&writeValue, sizeof(uint)); | ||
447 | file->write((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | 447 | store->write((char*)offsets.data(), sizeof(ItemDataInfo) * offsets.size()); | ||
448 | } | 448 | } | ||
449 | 449 | | |||
450 | //END DUChainItemStorage | 450 | //END DUChainItemStorage | ||
451 | 451 | | |||
452 | const char* TopDUContextDynamicData::pointerInData(uint totalOffset) const | 452 | const char* TopDUContextDynamicData::pointerInData(uint totalOffset) const | ||
453 | { | 453 | { | ||
454 | Q_ASSERT(!m_mappedData || m_data.isEmpty()); | 454 | Q_ASSERT(!m_mappedData || m_data.isEmpty()); | ||
455 | 455 | | |||
Show All 34 Lines | 489 | void KDevelop::TopDUContextDynamicData::unmap() { | |||
490 | delete m_mappedFile; | 490 | delete m_mappedFile; | ||
491 | m_mappedFile = nullptr; | 491 | m_mappedFile = nullptr; | ||
492 | m_mappedData = nullptr; | 492 | m_mappedData = nullptr; | ||
493 | m_mappedDataSize = 0; | 493 | m_mappedDataSize = 0; | ||
494 | } | 494 | } | ||
495 | 495 | | |||
496 | bool TopDUContextDynamicData::fileExists(uint topContextIndex) | 496 | bool TopDUContextDynamicData::fileExists(uint topContextIndex) | ||
497 | { | 497 | { | ||
498 | return QFile::exists(pathForTopContext(topContextIndex)); | 498 | return TopDUContextStore::exists(topContextIndex); | ||
499 | } | 499 | } | ||
500 | 500 | | |||
501 | QList<IndexedDUContext> TopDUContextDynamicData::loadImporters(uint topContextIndex) { | 501 | QList<IndexedDUContext> TopDUContextDynamicData::loadImporters(uint topContextIndex) { | ||
502 | QList<IndexedDUContext> ret; | 502 | QList<IndexedDUContext> ret; | ||
503 | loadTopDUContextData(topContextIndex, FullLoad, [&ret] (const TopDUContextData* topData) { | 503 | loadTopDUContextData(topContextIndex, FullLoad, [&ret] (const TopDUContextData* topData) { | ||
504 | ret.reserve(topData->m_importersSize()); | 504 | ret.reserve(topData->m_importersSize()); | ||
505 | FOREACH_FUNCTION(const IndexedDUContext& importer, topData->m_importers) | 505 | FOREACH_FUNCTION(const IndexedDUContext& importer, topData->m_importers) | ||
506 | ret << importer; | 506 | ret << importer; | ||
Show All 25 Lines | 530 | void TopDUContextDynamicData::loadData() const { | |||
532 | static QMutex mutex; | 532 | static QMutex mutex; | ||
533 | QMutexLocker lock(&mutex); | 533 | QMutexLocker lock(&mutex); | ||
534 | if(m_dataLoaded) | 534 | if(m_dataLoaded) | ||
535 | return; | 535 | return; | ||
536 | 536 | | |||
537 | Q_ASSERT(!m_dataLoaded); | 537 | Q_ASSERT(!m_dataLoaded); | ||
538 | Q_ASSERT(m_data.isEmpty()); | 538 | Q_ASSERT(m_data.isEmpty()); | ||
539 | 539 | | |||
540 | QFile* file = new QFile(pathForTopContext(m_topContext->ownIndex())); | 540 | TopDUContextStore* store = new TopDUContextStore(m_topContext->ownIndex()); | ||
541 | bool open = file->open(QIODevice::ReadOnly); | 541 | bool open = store->open(QIODevice::ReadOnly); | ||
542 | Q_UNUSED(open); | 542 | Q_UNUSED(open); | ||
543 | Q_ASSERT(open); | 543 | Q_ASSERT(open); | ||
544 | Q_ASSERT(file->size()); | 544 | Q_ASSERT(store->size()); | ||
545 | 545 | | |||
546 | //Skip the offsets, we're already read them | 546 | //Skip the offsets, we're already read them | ||
547 | //Skip top-context data | 547 | //Skip top-context data | ||
548 | uint readValue; | 548 | uint readValue; | ||
549 | file->read((char*)&readValue, sizeof(uint)); | 549 | store->read((char*)&readValue, sizeof(uint)); | ||
550 | file->seek(readValue + file->pos()); | 550 | store->seek(readValue + store->pos()); | ||
551 | 551 | | |||
552 | m_contexts.loadData(file); | 552 | m_contexts.loadData(store); | ||
553 | m_declarations.loadData(file); | 553 | m_declarations.loadData(store); | ||
554 | m_problems.loadData(file); | 554 | m_problems.loadData(store); | ||
555 | 555 | | |||
556 | #ifdef USE_MMAP | 556 | #ifdef USE_MMAP | ||
557 | 557 | | |||
558 | m_mappedData = file->map(file->pos(), file->size() - file->pos()); | 558 | m_mappedData = store->map(store->pos(), store->size() - store->pos()); | ||
559 | if(m_mappedData) { | 559 | if(m_mappedData) { | ||
560 | m_mappedFile = file; | 560 | m_mappedFile = store; | ||
561 | m_mappedDataSize = file->size() - file->pos(); | 561 | m_mappedDataSize = store->size() - store->pos(); | ||
562 | file->close(); //Close the file, so there is less open file descriptors(May be problematic) | 562 | store->commit(); //Close the store, so there are less open file descriptors (May be problematic) | ||
563 | }else{ | 563 | }else{ | ||
564 | qCDebug(LANGUAGE) << "Failed to map" << file->fileName(); | 564 | qCDebug(LANGUAGE) << "Failed to map" << store->fileName(); | ||
565 | } | 565 | } | ||
566 | 566 | | |||
567 | #endif | 567 | #endif | ||
568 | 568 | | |||
569 | if(!m_mappedFile) { | 569 | if(!m_mappedFile) { | ||
570 | QByteArray data = file->readAll(); | 570 | QByteArray data = store->readAll(); | ||
571 | m_data.append({data, (uint)data.size()}); | 571 | m_data.append({data, (uint)data.size()}); | ||
572 | delete file; | 572 | delete store; | ||
573 | } | 573 | } | ||
574 | 574 | | |||
575 | m_dataLoaded = true; | 575 | m_dataLoaded = true; | ||
576 | } | 576 | } | ||
577 | 577 | | |||
578 | TopDUContext* TopDUContextDynamicData::load(uint topContextIndex) { | 578 | TopDUContext* TopDUContextDynamicData::load(uint topContextIndex) { | ||
579 | QFile file(pathForTopContext(topContextIndex)); | 579 | TopDUContextStore store(topContextIndex); | ||
580 | if(file.open(QIODevice::ReadOnly)) { | 580 | if(store.open(QIODevice::ReadOnly)) { | ||
581 | if(file.size() == 0) { | 581 | if(store.size() == 0) { | ||
582 | qCWarning(LANGUAGE) << "Top-context file is empty" << file.fileName(); | 582 | qCWarning(LANGUAGE) << "Top-context store is empty" << store.fileName(); | ||
583 | return nullptr; | 583 | return nullptr; | ||
584 | } | 584 | } | ||
585 | QVector<ItemDataInfo> contextDataOffsets; | 585 | QVector<ItemDataInfo> contextDataOffsets; | ||
586 | QVector<ItemDataInfo> declarationDataOffsets; | 586 | QVector<ItemDataInfo> declarationDataOffsets; | ||
587 | 587 | | |||
588 | uint readValue; | 588 | uint readValue; | ||
589 | file.read((char*)&readValue, sizeof(uint)); | 589 | store.read((char*)&readValue, sizeof(uint)); | ||
590 | //now readValue is filled with the top-context data size | 590 | //now readValue is filled with the top-context data size | ||
591 | QByteArray topContextData = file.read(readValue); | 591 | QByteArray topContextData = store.read(readValue); | ||
592 | 592 | | |||
593 | DUChainBaseData* topData = reinterpret_cast<DUChainBaseData*>(topContextData.data()); | 593 | DUChainBaseData* topData = reinterpret_cast<DUChainBaseData*>(topContextData.data()); | ||
594 | TopDUContext* ret = dynamic_cast<TopDUContext*>(DUChainItemSystem::self().create(topData)); | 594 | TopDUContext* ret = dynamic_cast<TopDUContext*>(DUChainItemSystem::self().create(topData)); | ||
595 | if(!ret) { | 595 | if(!ret) { | ||
596 | qCWarning(LANGUAGE) << "Cannot load a top-context from file" << file.fileName() << "- the required language-support for handling ID" << topData->classId << "is probably not loaded"; | 596 | qCWarning(LANGUAGE) << "Cannot load a top-context from store" << store.fileName() << "- the required language-support for handling ID" << topData->classId << "is probably not loaded"; | ||
597 | return nullptr; | 597 | return nullptr; | ||
598 | } | 598 | } | ||
599 | 599 | | |||
600 | TopDUContextDynamicData& target(*ret->m_dynamicData); | 600 | TopDUContextDynamicData& target(*ret->m_dynamicData); | ||
601 | 601 | | |||
602 | target.m_data.clear(); | 602 | target.m_data.clear(); | ||
603 | target.m_dataLoaded = false; | 603 | target.m_dataLoaded = false; | ||
604 | target.m_onDisk = true; | 604 | target.m_onDisk = true; | ||
Show All 20 Lines | 617 | void TopDUContextDynamicData::deleteOnDisk() { | |||
625 | m_contexts.deleteOnDisk(); | 625 | m_contexts.deleteOnDisk(); | ||
626 | m_declarations.deleteOnDisk(); | 626 | m_declarations.deleteOnDisk(); | ||
627 | m_problems.deleteOnDisk(); | 627 | m_problems.deleteOnDisk(); | ||
628 | 628 | | |||
629 | m_topContext->makeDynamic(); | 629 | m_topContext->makeDynamic(); | ||
630 | 630 | | |||
631 | m_onDisk = false; | 631 | m_onDisk = false; | ||
632 | 632 | | |||
633 | bool successfullyRemoved = QFile::remove(filePath()); | 633 | bool successfullyRemoved = TopDUContextStore::remove(m_topContext->ownIndex()); | ||
634 | Q_UNUSED(successfullyRemoved); | 634 | Q_UNUSED(successfullyRemoved); | ||
635 | Q_ASSERT(successfullyRemoved); | 635 | Q_ASSERT(successfullyRemoved); | ||
636 | qCDebug(LANGUAGE) << "deletion ready"; | 636 | qCDebug(LANGUAGE) << "deletion ready"; | ||
637 | } | 637 | } | ||
638 | 638 | | |||
639 | QString TopDUContextDynamicData::basePath() | ||||
640 | { | ||||
641 | return globalItemRepositoryRegistry().path() + "/topcontexts/"; | ||||
642 | } | ||||
643 | | ||||
644 | QString TopDUContextDynamicData::pathForTopContext(const uint topContextIndex) | ||||
645 | { | ||||
646 | return basePath() + QString::number(topContextIndex); | ||||
647 | } | ||||
648 | | ||||
639 | QString KDevelop::TopDUContextDynamicData::filePath() const { | 649 | QString KDevelop::TopDUContextDynamicData::filePath() const { | ||
640 | return pathForTopContext(m_topContext->ownIndex()); | 650 | return pathForTopContext(m_topContext->ownIndex()); | ||
641 | } | 651 | } | ||
642 | 652 | | |||
643 | bool TopDUContextDynamicData::hasChanged() const | 653 | bool TopDUContextDynamicData::hasChanged() const | ||
644 | { | 654 | { | ||
645 | return !m_onDisk || m_topContext->d_func()->m_dynamic | 655 | return !m_onDisk || m_topContext->d_func()->m_dynamic | ||
646 | || m_contexts.itemsHaveChanged() || m_declarations.itemsHaveChanged() | 656 | || m_contexts.itemsHaveChanged() || m_declarations.itemsHaveChanged() | ||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Line(s) | 715 | } | |||
708 | Q_ASSERT(actualTopContextDataSize == topContextDataSize); | 718 | Q_ASSERT(actualTopContextDataSize == topContextDataSize); | ||
709 | Q_ASSERT(m_topContextData.size() == 1); | 719 | Q_ASSERT(m_topContextData.size() == 1); | ||
710 | Q_ASSERT(!m_topContext->d_func()->isDynamic()); | 720 | Q_ASSERT(!m_topContext->d_func()->isDynamic()); | ||
711 | 721 | | |||
712 | unmap(); | 722 | unmap(); | ||
713 | 723 | | |||
714 | QDir().mkpath(basePath()); | 724 | QDir().mkpath(basePath()); | ||
715 | 725 | | |||
716 | QFile file(filePath()); | 726 | QElapsedTimer timer; | ||
717 | if(file.open(QIODevice::WriteOnly)) { | 727 | qint64 nBytes = 0; | ||
728 | if (Q_LIKELY(QFileInfo(basePath()).isWritable())) { | ||||
729 | timer.start(); | ||||
730 | TopDUContextStore store(m_topContext->ownIndex()); | ||||
731 | if(store.open(QIODevice::WriteOnly)) { | ||||
718 | 732 | | |||
719 | file.resize(0); | 733 | store.resize(0); | ||
720 | 734 | | |||
721 | file.write((char*)&topContextDataSize, sizeof(uint)); | 735 | store.write((char*)&topContextDataSize, sizeof(uint)); | ||
722 | foreach(const ArrayWithPosition& pos, m_topContextData) | 736 | foreach(const ArrayWithPosition& pos, m_topContextData) | ||
723 | file.write(pos.array.constData(), pos.position); | 737 | store.write(pos.array.constData(), pos.position); | ||
724 | 738 | | |||
725 | m_contexts.writeData(&file); | 739 | m_contexts.writeData(&store); | ||
726 | m_declarations.writeData(&file); | 740 | m_declarations.writeData(&store); | ||
727 | m_problems.writeData(&file); | 741 | m_problems.writeData(&store); | ||
728 | 742 | | |||
729 | foreach(const ArrayWithPosition& pos, m_data) | 743 | foreach(const ArrayWithPosition& pos, m_data) | ||
730 | file.write(pos.array.constData(), pos.position); | 744 | store.write(pos.array.constData(), pos.position); | ||
731 | 745 | | |||
732 | m_onDisk = true; | 746 | m_onDisk = true; | ||
733 | 747 | | |||
734 | if (file.size() == 0) { | 748 | nBytes = store.size(); | ||
749 | if (store.size() == 0) { | ||||
735 | qCWarning(LANGUAGE) << "Saving zero size top ducontext data"; | 750 | qCWarning(LANGUAGE) << "Saving zero size top ducontext data"; | ||
736 | } | 751 | } | ||
737 | file.close(); | 752 | store.commit(); | ||
738 | } else { | 753 | } else { | ||
739 | qCWarning(LANGUAGE) << "Cannot open top-context for writing"; | 754 | qCWarning(LANGUAGE) << "Cannot open topcontext" << store.fileName() << "for writing:" << store.errorString(); | ||
740 | } | 755 | } | ||
741 | // qCDebug(LANGUAGE) << "stored" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size(); | 756 | // qCDebug(LANGUAGE) << "stored" << m_topContext->url().str() << m_topContext->ownIndex() << "import-count:" << m_topContext->importedParentContexts().size(); | ||
757 | } else { | ||||
758 | static bool warned = false; | ||||
759 | if (!warned) { | ||||
760 | qCWarning(LANGUAGE) << "Topcontexts directory" << basePath() << "is not writable, topcontext files won't be stored."; | ||||
761 | warned = true; | ||||
762 | } | ||||
763 | } | ||||
764 | if (timer.isValid()) { | ||||
765 | auto elapsed = timer.elapsed(); | ||||
766 | static quint64 totalBytes = 0; | ||||
767 | static double totalElapsed = 0.0; | ||||
768 | totalBytes += nBytes; | ||||
769 | totalElapsed += elapsed / 1000.0; | ||||
770 | if (totalBytes && totalElapsed >= 0.5) { | ||||
771 | qCInfo(LANGUAGE) << "Stored" << totalBytes << "topcontext bytes at" << totalBytes / totalElapsed << "bytes/second"; | ||||
772 | totalBytes = 0, totalElapsed = 0.0; | ||||
773 | } | ||||
774 | } | ||||
742 | } | 775 | } | ||
743 | 776 | | |||
744 | TopDUContextDynamicData::ItemDataInfo TopDUContextDynamicData::writeDataInfo(const ItemDataInfo& info, const DUChainBaseData* data, uint& totalDataOffset) { | 777 | TopDUContextDynamicData::ItemDataInfo TopDUContextDynamicData::writeDataInfo(const ItemDataInfo& info, const DUChainBaseData* data, uint& totalDataOffset) { | ||
745 | ItemDataInfo ret(info); | 778 | ItemDataInfo ret(info); | ||
746 | Q_ASSERT(info.dataOffset); | 779 | Q_ASSERT(info.dataOffset); | ||
747 | const auto size = DUChainItemSystem::self().dynamicSize(*data); | 780 | const auto size = DUChainItemSystem::self().dynamicSize(*data); | ||
748 | Q_ASSERT(size); | 781 | Q_ASSERT(size); | ||
749 | 782 | | |||
▲ Show 20 Lines • Show All 92 Lines • Show Last 20 Lines |