bool FS::tryGC()

in libs/settings/RAFFS.cpp [395:499]


bool FS::tryGC(int spaceNeeded, filename_filter filter) {
    int spaceLeft = (intptr_t)metaPtr - (intptr_t)freeDataPtr;

#ifdef RAFFS_TEST
    for (auto p = (uint32_t *)freeDataPtr; p < (uint32_t *)metaPtr; p++) {
        if (*p != M1) {
            LOG("value at %x = %x", OFF(p), *p);
            oopsAndClear();
        }
    }
#endif

    if (spaceLeft > spaceNeeded + 32)
        return true;
    
    int now = (int)system_timer_current_time();
    if (minGCSpacing) {
        gcHorizon += minGCSpacing;
        int nextGC = now - minGCSpacing * 2;
        // LOG("now=%d n=%d gch=%d", now, nextGC, gcHorizon);
        if (nextGC > gcHorizon)
            gcHorizon = nextGC;
        if (gcHorizon > now)
            target_panic(921);
    }

    LOG("running flash FS GC; needed %d, left %d", spaceNeeded, spaceLeft);

    readDirPtr = NULL;
    cachedMeta = NULL;

    auto newBase = (uintptr_t)altBasePtr();

    flushFlash();

    erasePages(newBase, bytes / 2);

    auto metaDst = (MetaEntry *)(newBase + bytes / 2);
    auto newBaseP = (uint8_t *)newBase;
    freeDataPtr = newBaseP + sizeof(FSHeader);

    for (int iter = 0; iter < 2; ++iter) {
        clearBlocked();
        auto offset = sizeof(FSHeader);
        for (auto p = metaPtr; p < endPtr; p++) {
            MetaEntry m = *p;
            const char *fn = fnptr(&m);

            if (filter && !filter(fn))
                continue;

            if (checkBlocked(&m) || m.dataptr == 0)
                continue;

            LOGV("GC %s sz=%d @%x", fn, m.datasize(), m.dataptr);
            auto fnlen = strlen(fn) + 1;
            auto sz = fnlen + m.datasize();

            if (iter == 0) {
                auto fd = freeDataPtr;
                writeData(fn, fnlen);
                writeData(basePtr + m.dataptr, m.datasize());
                if (freeDataPtr - fd != (int)sz)
                    oops();
            } else {
                m.fnptr = offset;
                m.dataptr = offset + fnlen;
                m._datasize &= ~RAFFS_FOLLOWING_MASK;
                writeBytes(--metaDst, &m, sizeof(m));
            }
            offset += sz;
        }
        if (iter == 0)
            finishWrite();
    }

    clearBlocked();
    flushFlash();

    LOG("GC done: %d free", (int)((intptr_t)metaDst - (intptr_t)freeDataPtr));

    FSHeader hd;
    hd.magic = RAFFS_MAGIC;
    hd.bytes = bytes;
    hd.numgc = ((FSHeader*)basePtr)->numgc + 1;
    hd.reserved = M1;
    writeBytes(newBaseP, &hd, sizeof(hd));
    flushFlash();

    basePtr = newBaseP;
    endPtr = (MetaEntry *)(newBase + bytes / 2);
    metaPtr = metaDst;

    if ((intptr_t)metaDst - (intptr_t)freeDataPtr <= spaceNeeded + 64) {
        if (filter != NULL && spaceNeeded != 0x7fff0000) {
            LOG("out of space! needed=%d", spaceNeeded);
#ifdef RAFFS_TEST
            oops();
#endif
        }
        return false;
    }

    return true;
}