📄 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 + pos;
at45pageoffset_t offset = s[client].woffset, count;
storage_len_t len = s[client].len - pos;
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].wpos += count;
s[client].woffset += count;
pos += 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 len = s[client].len - pos;
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 + pos;
at45pageoffset_t offset = s[client].roffset, count;
at45pageoffset_t end = s[client].rend;
storage_len_t len = s[client].len - pos;
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;
pos += 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 + -