📄 logstoragep.nc
字号:
readMetadata(firstPage); } void located() { metaState = META_LOCATELAST; /* firstPage is one after last valid page, but the last page with a record end may be some pages earlier. Search for it. */ lastPage = lastVolumePage() - 1; locateLastRecord(); } at45page_t locateCurrentPage() { return firstPage + ((lastPage - firstPage) >> 1); } void locateBinarySearch() { if (lastPage <= firstPage) located(); else readMetadata(locateCurrentPage()); } void locateGreaterThan() { firstPage = locateCurrentPage() + 1; locateBinarySearch(); } void locateLessThan() { lastPage = locateCurrentPage(); locateBinarySearch(); } void locateCrcDone(uint16_t crc) { if (crc == metadata.crc) { s[client].wpos = metadata.pos; locateGreaterThan(); } else locateLessThan(); } void locateReadDone() { if (metadata.magic == PERSISTENT_MAGIC && s[client].wpos < metadata.pos) crcPage(locateCurrentPage()); else locateLessThan(); } void locateFirstCrcDone(uint16_t crc) { if (metadata.magic == PERSISTENT_MAGIC && crc == metadata.crc) s[client].wpos = metadata.pos; else s[client].wpos = 0; metaState = META_LOCATE; locateBinarySearch(); } void locateFirstReadDone() { crcPage(lastPage); } /* Locate log beginning and ending. See description at top of file. */ void locateStart() { metaState = META_LOCATEFIRST; firstPage = firstVolumePage(); lastPage = lastVolumePage() - 1; readMetadata(lastPage); } /* ------------------------------------------------------------------ */ /* Append */ /* ------------------------------------------------------------------ */ void appendContinue() { uint8_t *buf = s[client].buf; at45pageoffset_t offset = s[client].woffset, count; if (len == 0) { endRequest(SUCCESS); return; } if (s[client].wpage == lastVolumePage()) { /* We reached the end of a linear log */ endRequest(ESIZE); return; } if (offset + len <= PAGE_SIZE) count = len; else count = PAGE_SIZE - offset; s[client].buf += count; s[client].wpos += count; s[client].woffset += count; len -= count; /* We normally lose data at the point we make the first write to a page in a log that has circled. */ if (offset == 0 && s[client].circled) recordsLost = TRUE; call At45db.write(s[client].wpage, offset, buf, count); } void appendWriteDone() { if (s[client].woffset == PAGE_SIZE) /* Time to write metadata */ wmetadataStart(); else endRequest(SUCCESS); } void appendMetadataDone() { // metadata of previous page flushed /* Setup metadata in case we overflow this page too */ metadata.flags = 0; appendContinue(); } void appendSyncDone() { s[client].wpos = metadata.pos + PAGE_SIZE; appendStart(); } void appendStart() { storage_len_t vlen = (storage_len_t)npages() * PAGE_SIZE; recordsLost = FALSE; /* If request would span the end of the flash, sync, to maintain the invariant that the last flash page is synced and that either the first or last pages are valid. Note that >= in the if below means we won't write a record that would end on the last byte of the last page, as this would mean that we would not sync the last page, breaking the log volume invariant */ if ((s[client].wpos - PAGE_SIZE) % vlen >= vlen - len) sync(); else { /* Set lastRecordOffset in case we need to write metadata (see wmetadataStart) */ metadata.lastRecordOffset = s[client].woffset; metadata.flags = F_LASTVALID; appendContinue(); } } /* ------------------------------------------------------------------ */ /* Sync */ /* ------------------------------------------------------------------ */ void syncStart() { if (s[client].woffset == 0) /* we can't lose any writes */ endRequest(SUCCESS); else sync(); } void syncMetadataDone() { /* Write position reflect the absolute position in the flash, not user-bytes written. So update wpos to reflect sync effects. */ s[client].wpos = metadata.pos + PAGE_SIZE; endRequest(SUCCESS); } /* ------------------------------------------------------------------ */ /* Write block metadata */ /* ------------------------------------------------------------------ */ void wmetadataStart() { /* The caller ensures that metadata.flags (except F_CIRCLED) and metadata.lastRecordOffset are set correctly. */ metaState = META_WRITE; firstPage = s[client].wpage; // remember page to commit metadata.pos = s[client].wpos - s[client].woffset; metadata.magic = PERSISTENT_MAGIC; if (s[client].circled) metadata.flags |= F_CIRCLED; call At45db.computeCrc(firstPage, 0, PAGE_SIZE, 0); /* We move to the next page now. If writing the metadata fails, we'll simply leave the invalid page in place. Trying to recover seems complicated, and of little benefit (note that in practice, At45dbC shuts down after a failed write, so nothing is really going to happen after that anyway). */ setWritePage(s[client].wpage + 1); /* Invalidate read pointer if we reach it's page */ if (s[client].wpage == s[client].rpage) invalidateReadPointer(); } void wmetadataCrcDone(uint16_t crc) { uint8_t i, *md; // Include metadata in crc md = (uint8_t *)&metadata; for (i = 0; i < offsetof(nx_struct pageinfo, crc); i++) crc = crcByte(crc, md[i]); metadata.crc = crc; // And save it writeMetadata(firstPage); } void wmetadataWriteDone() { metaState = META_IDLE; if (metadata.flags & F_SYNC) call At45db.sync(firstPage); else call At45db.flush(firstPage); } /* ------------------------------------------------------------------ */ /* Read */ /* ------------------------------------------------------------------ */ void readContinue() { uint8_t *buf = s[client].buf; at45pageoffset_t offset = s[client].roffset, count; at45pageoffset_t end = s[client].rend; if (len == 0) { endRequest(SUCCESS); return; } if (!s[client].rvalid) { if (s[client].circled) /* Find a valid page after wpage, skipping invalid pages */ s[client].rpage = s[client].wpage; else { /* resume reading at the beginning of the first page */ s[client].rvalid = TRUE; s[client].rpage = lastVolumePage() - 1; } rmetadataStart(); return; } if (s[client].rpage == s[client].wpage) end = s[client].woffset; if (offset == end) { if ((s[client].rpage + 1 == lastVolumePage() && !s[client].circular) || s[client].rpage == s[client].wpage) endRequest(SUCCESS); // end of log else rmetadataStart(); return; } if (offset + len <= end) count = len; else count = end - offset; s[client].buf += count; len -= count; s[client].rpos += count; s[client].roffset = offset + count; call At45db.read(s[client].rpage, offset, buf, count); } void readStart() { readContinue(); } /* ------------------------------------------------------------------ */ /* Read block metadata */ /* ------------------------------------------------------------------ */ void continueReadAt(at45pageoffset_t roffset) { /* Resume reading at firstPage whose metadata is currently available in the metadata variable */ metaState = META_IDLE; s[client].rpos = metadata.pos + roffset; s[client].rpage = firstPage; s[client].roffset = roffset; s[client].rend = metadata.flags & F_SYNC ? metadata.lastRecordOffset : PAGE_SIZE; s[client].rvalid = TRUE; readContinue(); } void rmetadataContinue() { if (++firstPage == lastVolumePage()) firstPage = firstVolumePage(); if (firstPage == s[client].wpage) if (!s[client].rvalid) /* We cannot find a record boundary to start at (we've just walked through the whole log...). Give up. */ endRequest(SUCCESS); else { /* The current write page has no metadata yet, so we fake it */ metadata.flags = 0; metadata.pos = s[client].wpos - s[client].woffset; continueReadAt(0); } else readMetadata(firstPage); } void rmetadataReadDone() { if (metadata.magic == PERSISTENT_MAGIC) crcPage(firstPage); else endRequest(SUCCESS); } void rmetadataCrcDone(uint16_t crc) { if (!s[client].rvalid) if (crc == metadata.crc && metadata.flags & F_LASTVALID) continueReadAt(metadata.lastRecordOffset); else rmetadataContinue(); else if (crc == metadata.crc) continueReadAt(0); else endRequest(SUCCESS); } void rmetadataStart() { metaState = META_READ; firstPage = s[client].rpage; rmetadataContinue(); } /* ------------------------------------------------------------------ */ /* Seek. */ /* ------------------------------------------------------------------ */ void seekCrcDone(uint16_t crc) { if (metadata.magic == PERSISTENT_MAGIC && crc == metadata.crc && metadata.pos == s[client].rpos - s[client].roffset) { s[client].rvalid = TRUE; if (metadata.flags & F_SYNC) s[client].rend = metadata.lastRecordOffset; } endRequest(SUCCESS); } void seekReadDone() { crcPage(s[client].rpage); } /* Move to position specified by cookie. */ void seekStart() { uint32_t offset = (uint32_t)(uint16_t)s[client].buf << 16 | s[client].len; invalidateReadPointer(); // default to beginning of log /* The write positions are offset by PAGE_SIZE (see emptyLog) */ if (offset == SEEK_BEGINNING) offset = PAGE_SIZE; if (offset > s[client].wpos || offset < PAGE_SIZE) { endRequest(EINVAL); return; } /* Cookies are just flash positions which continue incrementing as you circle around and around. So we can just check the requested page's metadata.pos field matches the cookie's value */ s[client].rpos = offset; s[client].roffset = (offset - PAGE_SIZE) % PAGE_SIZE; s[client].rpage = firstVolumePage() + ((offset - PAGE_SIZE) / PAGE_SIZE) % npages(); s[client].rend = PAGE_SIZE; // default to no sync flag // The last page's metadata isn't written to flash yet. Special case it. if (s[client].rpage == s[client].wpage) { /* If we're seeking within the current write page, just go there. Otherwise, we're asking for an old version of the current page so just keep the invalidated read pointer, i.e., read from the beginning. */ if (offset >= s[client].wpos - s[client].woffset) s[client].rvalid = TRUE; endRequest(SUCCESS); } else { metaState = META_SEEK; readMetadata(s[client].rpage); } } /* ------------------------------------------------------------------ */ /* Dispatch HAL operations to current user op */ /* ------------------------------------------------------------------ */ event void At45db.eraseDone(error_t error) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else eraseEraseDone(); } event void At45db.writeDone(error_t error) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else switch (metaState) { case META_WRITE: wmetadataWriteDone(); break; case META_IDLE: appendWriteDone(); break; } } event void At45db.syncDone(error_t error) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else switch (s[client].request) { case R_ERASE: eraseMetadataDone(); break; case R_APPEND: appendSyncDone(); break; case R_SYNC: syncMetadataDone(); break; } } event void At45db.flushDone(error_t error) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else appendMetadataDone(); } event void At45db.readDone(error_t error) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else switch (metaState) { case META_LOCATEFIRST: locateFirstReadDone(); break; case META_LOCATE: locateReadDone(); break; case META_LOCATELAST: locateLastReadDone(); break; case META_SEEK: seekReadDone(); break; case META_READ: rmetadataReadDone(); break; case META_IDLE: readContinue(); break; } } event void At45db.computeCrcDone(error_t error, uint16_t crc) { if (client != NO_CLIENT) if (error != SUCCESS) endRequest(FAIL); else switch (metaState) { case META_LOCATEFIRST: locateFirstCrcDone(crc); break; case META_LOCATE: locateCrcDone(crc); break; case META_LOCATELAST: locateLastCrcDone(crc); break; case META_SEEK: seekCrcDone(crc); break; case META_WRITE: wmetadataCrcDone(crc); break; case META_READ: rmetadataCrcDone(crc); break; } } event void At45db.copyPageDone(error_t error) { } default event void LogWrite.appendDone[uint8_t logId](void* buf, storage_len_t l, bool rLost, error_t error) { } default event void LogWrite.eraseDone[uint8_t logId](error_t error) { } default event void LogWrite.syncDone[uint8_t logId](error_t error) { } default event void LogRead.readDone[uint8_t logId](void* buf, storage_len_t l, error_t error) { } default event void LogRead.seekDone[uint8_t logId](error_t error) {} default command at45page_t At45dbVolume.remap[uint8_t logId](at45page_t volumePage) {return 0;} default command at45page_t At45dbVolume.volumeSize[uint8_t logId]() {return 0;} default async command error_t Resource.request[uint8_t logId]() {return SUCCESS;} default async command error_t Resource.release[uint8_t logId]() { return FAIL; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -