This is an automated email from the ASF dual-hosted git repository.

marko pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-core.git

commit 43da6d720ba4bfb608c1766f949b8a47dd5253b2
Author: Marko Kiiskila <ma...@apache.org>
AuthorDate: Wed Aug 28 10:33:03 2019 +0300

    fs/fcb2; add fcb_getprev() to walk backwards within FCB.
---
 fs/fcb2/include/fcb/fcb.h                          |   3 +-
 fs/fcb2/selftest/src/fcb_test.c                    |   2 +
 fs/fcb2/selftest/src/testcases/fcb_test_getprev.c  | 140 +++++++++++++++++++++
 .../selftest/src/testcases/fcb_test_last_of_n.c    |  34 ++---
 fs/fcb2/src/fcb.c                                  |  27 ++--
 fs/fcb2/src/fcb_elem_info.c                        |   2 +-
 fs/fcb2/src/fcb_getnext.c                          |   6 -
 fs/fcb2/src/fcb_getprev.c                          | 102 +++++++++++++++
 fs/fcb2/src/fcb_priv.h                             |   1 -
 9 files changed, 276 insertions(+), 41 deletions(-)

diff --git a/fs/fcb2/include/fcb/fcb.h b/fs/fcb2/include/fcb/fcb.h
index 83b99fd..1b4049d 100644
--- a/fs/fcb2/include/fcb/fcb.h
+++ b/fs/fcb2/include/fcb/fcb.h
@@ -138,6 +138,7 @@ int fcb_append_finish(struct fcb_entry *append_loc);
 typedef int (*fcb_walk_cb)(struct fcb_entry *loc, void *arg);
 int fcb_walk(struct fcb *, int sector, fcb_walk_cb cb, void *cb_arg);
 int fcb_getnext(struct fcb *fcb, struct fcb_entry *loc);
+int fcb_getprev(struct fcb *fcb, struct fcb_entry *loc);
 int fcb_read(struct fcb_entry *loc, uint16_t off, void *buf, uint16_t len);
 
 /**
@@ -165,7 +166,7 @@ int fcb_is_empty(struct fcb *fcb);
  */
 int
 fcb_offset_last_n(struct fcb *fcb, uint8_t entries,
-        struct fcb_entry *last_n_entry);
+                  struct fcb_entry *last_n_entry);
 
 /**
  * Erase sector in FCB
diff --git a/fs/fcb2/selftest/src/fcb_test.c b/fs/fcb2/selftest/src/fcb_test.c
index a16e40c..0a29f55 100644
--- a/fs/fcb2/selftest/src/fcb_test.c
+++ b/fs/fcb2/selftest/src/fcb_test.c
@@ -141,6 +141,7 @@ TEST_CASE_DECL(fcb_test_rotate)
 TEST_CASE_DECL(fcb_test_multiple_scratch)
 TEST_CASE_DECL(fcb_test_last_of_n)
 TEST_CASE_DECL(fcb_test_area_info)
+TEST_CASE_DECL(fcb_test_getprev)
 
 TEST_SUITE(fcb_test_all)
 {
@@ -154,6 +155,7 @@ TEST_SUITE(fcb_test_all)
     fcb_test_multiple_scratch();
     fcb_test_last_of_n();
     fcb_test_area_info();
+    fcb_test_getprev();
 }
 
 int
diff --git a/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c 
b/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c
new file mode 100644
index 0000000..ec1a255
--- /dev/null
+++ b/fs/fcb2/selftest/src/testcases/fcb_test_getprev.c
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include "fcb_test.h"
+
+TEST_CASE_SELF(fcb_test_getprev)
+{
+    struct fcb *fcb = &test_fcb;
+    struct fcb_entry loc;
+    struct fcb_entry prev;
+    int rc;
+    int i, j;
+
+    fcb_tc_pretest(3);
+
+    prev.fe_range = NULL;
+
+    /*
+     * Empty FCB returns error.
+     */
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT_FATAL(rc == FCB_ERR_NOVAR);
+
+    /*
+     * Add one entry. getprev should find that guy, and then error.
+     */
+    rc = fcb_append(fcb, 8, &loc);
+    TEST_ASSERT(rc == 0);
+    rc = fcb_append_finish(&loc);
+    TEST_ASSERT(rc == 0);
+
+    prev.fe_range = NULL;
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT_FATAL(rc == 0);
+    TEST_ASSERT(!memcmp(&loc, &prev, sizeof(loc)));
+
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT(rc == FCB_ERR_NOVAR);
+
+    /*
+     * Add enough entries to go to 2 sectors, should find them all.
+     */
+    fcb_tc_pretest(3);
+    for (i = 0; ; i++) {
+        rc = fcb_append(fcb, i + 1, &loc);
+        TEST_ASSERT(rc == 0);
+        rc = fcb_append_finish(&loc);
+        TEST_ASSERT(rc == 0);
+
+        if (loc.fe_sector == prev.fe_sector + 2) {
+            break;
+        }
+    }
+
+    prev.fe_range = NULL;
+    for (j = i; j >= 0; j--) {
+        rc = fcb_getprev(fcb, &prev);
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(prev.fe_data_len == j + 1);
+    }
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT(rc == FCB_ERR_NOVAR);
+
+    /*
+     * Clean the area. Fill 2 whole sectors with corrupt entries. And one
+     * good one. Should find the one good one, followed by error
+     */
+    fcb_tc_pretest(3);
+
+    for (i = 0; ; i++) {
+        rc = fcb_append(fcb, i + 1, &loc);
+        TEST_ASSERT(rc == 0);
+
+        if (loc.fe_sector == prev.fe_sector + 2) {
+            rc = fcb_append_finish(&loc);
+            TEST_ASSERT(rc == 0);
+            break;
+        }
+    }
+
+    prev.fe_range = NULL;
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT_FATAL(rc == 0);
+    TEST_ASSERT(!memcmp(&loc, &prev, sizeof(loc)));
+
+    rc = fcb_getprev(fcb, &prev);
+    TEST_ASSERT(rc == FCB_ERR_NOVAR);
+
+    /*
+     * Create new. Rotate one sector, should be able to follow
+     * from end of range to start.
+     */
+
+    fcb_tc_pretest(3);
+
+    for (i = 0; ; i++) {
+        rc = fcb_append(fcb, i + 8, &loc);
+        if (rc == FCB_ERR_NOSPACE) {
+            break;
+        }
+        TEST_ASSERT(rc == 0);
+        rc = fcb_append_finish(&loc);
+        TEST_ASSERT(rc == 0);
+    }
+
+    /*
+     * Full. Rotate, add one more, and then walk backwards.
+     */
+    fcb_rotate(fcb);
+
+    rc = fcb_append(fcb, i + 8, &loc);
+    TEST_ASSERT(rc == 0);
+    rc = fcb_append_finish(&loc);
+    TEST_ASSERT(rc == 0);
+
+    for (j = i; j >= 0; j--) {
+        rc = fcb_getprev(fcb, &prev);
+        if (rc == FCB_ERR_NOVAR) {
+            TEST_ASSERT(i > 0);
+            break;
+        }
+        TEST_ASSERT(rc == 0);
+        TEST_ASSERT(prev.fe_data_len == j + 8);
+    }
+}
diff --git a/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c 
b/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c
index 10ca3d7..2a6c3cd 100644
--- a/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c
+++ b/fs/fcb2/selftest/src/testcases/fcb_test_last_of_n.c
@@ -35,7 +35,7 @@ TEST_CASE_SELF(fcb_test_last_of_n)
 
     /* No fcbs available */
     rc = fcb_offset_last_n(fcb, 1, &loc);
-    assert (rc != 0);
+    TEST_ASSERT(rc != 0);
 
     /*
      * Add some fcbs.
@@ -57,29 +57,29 @@ TEST_CASE_SELF(fcb_test_last_of_n)
 
     /* last entry */
     rc = fcb_offset_last_n(fcb, 1, &loc);
-    assert (rc == 0);
-    assert (areas[4].fe_sector == loc.fe_sector);
-    assert (areas[4].fe_data_off == loc.fe_data_off);
-    assert (areas[4].fe_data_len == loc.fe_data_len);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(areas[4].fe_sector == loc.fe_sector);
+    TEST_ASSERT(areas[4].fe_data_off == loc.fe_data_off);
+    TEST_ASSERT(areas[4].fe_data_len == loc.fe_data_len);
 
     /* somewhere in the middle */
     rc = fcb_offset_last_n(fcb, 3, &loc);
-    assert (rc == 0);
-    assert (areas[2].fe_sector == loc.fe_sector);
-    assert (areas[2].fe_data_off == loc.fe_data_off);
-    assert (areas[2].fe_data_len == loc.fe_data_len);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(areas[2].fe_sector == loc.fe_sector);
+    TEST_ASSERT(areas[2].fe_data_off == loc.fe_data_off);
+    TEST_ASSERT(areas[2].fe_data_len == loc.fe_data_len);
 
     /* first entry */
     rc = fcb_offset_last_n(fcb, 5, &loc);
-    assert (rc == 0);
-    assert (areas[0].fe_sector == loc.fe_sector);
-    assert (areas[0].fe_data_off == loc.fe_data_off);
-    assert (areas[0].fe_data_len == loc.fe_data_len);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(areas[0].fe_sector == loc.fe_sector);
+    TEST_ASSERT(areas[0].fe_data_off == loc.fe_data_off);
+    TEST_ASSERT(areas[0].fe_data_len == loc.fe_data_len);
 
     /* after last valid entry, returns the first one like for 5 */
     rc = fcb_offset_last_n(fcb, 6, &loc);
-    assert (rc == 0);
-    assert (areas[0].fe_sector == loc.fe_sector);
-    assert (areas[0].fe_data_off == loc.fe_data_off);
-    assert (areas[0].fe_data_len == loc.fe_data_len);
+    TEST_ASSERT(rc == 0);
+    TEST_ASSERT(areas[0].fe_sector == loc.fe_sector);
+    TEST_ASSERT(areas[0].fe_data_off == loc.fe_data_off);
+    TEST_ASSERT(areas[0].fe_data_len == loc.fe_data_len);
 }
diff --git a/fs/fcb2/src/fcb.c b/fs/fcb2/src/fcb.c
index 3ec9cf2..80451d6 100644
--- a/fs/fcb2/src/fcb.c
+++ b/fs/fcb2/src/fcb.c
@@ -122,7 +122,8 @@ fcb_is_empty(struct fcb *fcb)
 {
     return (fcb->f_active.fe_sector == fcb->f_oldest_sec &&
         fcb->f_active.fe_data_off ==
-            fcb_len_in_flash(fcb->f_active.fe_range, sizeof(struct 
fcb_disk_area)));
+            fcb_len_in_flash(fcb->f_active.fe_range,
+                             sizeof(struct fcb_disk_area)));
 }
 
 struct flash_sector_range *
@@ -217,10 +218,8 @@ fcb_sector_hdr_read(struct fcb *fcb, struct 
flash_sector_range *srp,
  * @return 0 on there are any fcbs aviable; OS_ENOENT otherwise
  */
 int
-fcb_offset_last_n(struct fcb *fcb, uint8_t entries,
-        struct fcb_entry *last_n_entry)
+fcb_offset_last_n(struct fcb *fcb, uint8_t entries, struct fcb_entry *loc)
 {
-    struct fcb_entry loc;
     int i;
 
     /* assure a minimum amount of entries */
@@ -229,19 +228,16 @@ fcb_offset_last_n(struct fcb *fcb, uint8_t entries,
     }
 
     i = 0;
-    memset(&loc, 0, sizeof(loc));
-    while (!fcb_getnext(fcb, &loc)) {
-        if (i == 0) {
-            /* Start from the beginning of fcb entries */
-            *last_n_entry = loc;
-        } else if (i > (entries - 1)) {
-            /* Update last_n_entry after n entries and keep updating */
-            fcb_getnext(fcb, last_n_entry);
-        }
+    memset(loc, 0, sizeof(*loc));
+    while (!fcb_getprev(fcb, loc)) {
+        --entries;
         i++;
+        if (entries == 0) {
+            break;
+        }
     }
 
-    return (i == 0) ? OS_ENOENT : 0;
+    return (i == 0) ? FCB_ERR_NOVAR : 0;
 }
 
 /**
@@ -285,7 +281,8 @@ fcb_init_flash_area(struct fcb *fcb, int flash_area_id, 
uint32_t magic,
     assert(rc == 0 && sector_range_cnt > 0);
     sector_ranges = malloc(sizeof(struct flash_sector_range) * 
sector_range_cnt);
     assert(sector_ranges);
-    rc = flash_area_to_sector_ranges(flash_area_id, &sector_range_cnt, 
sector_ranges);
+    rc = flash_area_to_sector_ranges(flash_area_id, &sector_range_cnt,
+                                     sector_ranges);
     assert(rc == 0 && sector_range_cnt > 0);
 
     fcb->f_ranges = sector_ranges;
diff --git a/fs/fcb2/src/fcb_elem_info.c b/fs/fcb2/src/fcb_elem_info.c
index 413eea2..a222f36 100644
--- a/fs/fcb2/src/fcb_elem_info.c
+++ b/fs/fcb2/src/fcb_elem_info.c
@@ -57,7 +57,7 @@ fcb_elem_crc16(struct fcb_entry *loc, uint16_t *c16p)
     return 0;
 }
 
-int
+static int
 fcb_read_entry(struct fcb_entry *loc)
 {
     uint8_t buf[FCB_ENTRY_SIZE];
diff --git a/fs/fcb2/src/fcb_getnext.c b/fs/fcb2/src/fcb_getnext.c
index 4284afe..f90e26d 100644
--- a/fs/fcb2/src/fcb_getnext.c
+++ b/fs/fcb2/src/fcb_getnext.c
@@ -59,9 +59,6 @@ fcb_getnext_nolock(struct fcb *fcb, struct fcb_entry *loc)
          * If offset is zero, we serve the first entry from the area.
          */
         loc->fe_entry_num = 1;
-        loc->fe_data_off =
-            fcb_len_in_flash(loc->fe_range, sizeof(struct fcb_disk_area));
-        loc->fe_data_len = 0;
         rc = fcb_elem_info(loc);
     } else {
         rc = fcb_getnext_in_area(fcb, loc);
@@ -91,9 +88,6 @@ next_sector:
             loc->fe_sector = fcb_getnext_sector(fcb, loc->fe_sector);
             loc->fe_range = fcb_get_sector_range(fcb, loc->fe_sector);
             loc->fe_entry_num = 1;
-            loc->fe_data_off =
-                fcb_len_in_flash(loc->fe_range, sizeof(struct fcb_disk_area));
-            loc->fe_data_len = 0;
             rc = fcb_elem_info(loc);
             switch (rc) {
             case 0:
diff --git a/fs/fcb2/src/fcb_getprev.c b/fs/fcb2/src/fcb_getprev.c
new file mode 100644
index 0000000..6cdbe33
--- /dev/null
+++ b/fs/fcb2/src/fcb_getprev.c
@@ -0,0 +1,102 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <stddef.h>
+
+#include "fcb/fcb.h"
+#include "fcb_priv.h"
+
+static int
+fcb_sector_find_last(struct fcb *fcb, struct fcb_entry *loc)
+{
+    int rc;
+    int last_valid = 0;
+
+    loc->fe_entry_num = 1;
+
+    do {
+        rc = fcb_elem_info(loc);
+        if (rc == 0) {
+            last_valid = loc->fe_entry_num;
+        }
+        if (rc == FCB_ERR_NOVAR) {
+            /*
+             * Out entries in this sector
+             */
+            if (last_valid == 0) {
+                loc->fe_entry_num = 1;
+                /*
+                 * No valid entries in this sector.
+                 */
+                return FCB_ERR_NOVAR;
+            } else {
+                loc->fe_entry_num = last_valid;
+                rc = fcb_elem_info(loc);
+                assert(rc == 0); /* must be; just succeeded a bit earlier */
+                return rc;
+            }
+        }
+        loc->fe_entry_num++;
+    } while (1);
+    return rc;
+}
+
+int
+fcb_getprev(struct fcb *fcb, struct fcb_entry *loc)
+{
+    int rc;
+
+    rc = os_mutex_pend(&fcb->f_mtx, OS_WAIT_FOREVER);
+    if (rc && rc != OS_NOT_STARTED) {
+        return FCB_ERR_ARGS;
+    }
+    if (loc->fe_range == NULL) {
+        /*
+         * Find the last element.
+         */
+        *loc = fcb->f_active;
+    }
+    do {
+        loc->fe_entry_num--;
+        if (loc->fe_entry_num < 1) {
+            /*
+             * Need to get from previous sector.
+             */
+            if (loc->fe_sector == fcb->f_oldest_sec) {
+                return FCB_ERR_NOVAR;
+            }
+            if (loc->fe_sector == 0) {
+                loc->fe_sector = fcb->f_sector_cnt - 1;
+            } else {
+                loc->fe_sector--;
+            }
+            loc->fe_range = fcb_get_sector_range(fcb, loc->fe_sector);
+            rc = fcb_sector_find_last(fcb, loc);
+            if (rc == 0) {
+                break;
+            }
+        } else {
+            rc = fcb_elem_info(loc);
+            if (rc == 0) {
+                break;
+            }
+        }
+    } while (1);
+    os_mutex_release(&fcb->f_mtx);
+    return rc;
+}
diff --git a/fs/fcb2/src/fcb_priv.h b/fs/fcb2/src/fcb_priv.h
index 63f18e3..a1ec9d5 100644
--- a/fs/fcb2/src/fcb_priv.h
+++ b/fs/fcb2/src/fcb_priv.h
@@ -67,7 +67,6 @@ int fcb_elem_crc16(struct fcb_entry *loc, uint16_t *c16p);
 int fcb_sector_hdr_init(struct fcb *fcb, int sector, uint16_t id);
 int fcb_entry_location_in_range(const struct fcb_entry *loc);
 
-
 struct flash_sector_range *fcb_get_sector_range(const struct fcb *fcb,
     int sector);
 

Reply via email to