We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] dataset_meta.json isn't updated after create_tensor
## 🐛🐛 Bug Report

After loading an existing dataset with hub.dataset, create_tensor doesn't update the "tensors" attribute in dataset_meta.json.

### ⚗️ Current Behavior

For example, a dataset called "hub_dataset" with tensor "images" already exists. Loading it with hub.dataset then appending a new tensor, "test":

```python
ds = hub.dataset("hub_dataset")
ds.create_tensor('test')
```
The "tensors" attribute in dataset_meta.json won't contain the "test" tensor.

```json
{"version": "2.0.8", "tensors": ["images"]}
```

### ⚙️ Environment
- `Python` version(s): [3.7.11]
- `OS`: Ubuntu 18.04

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `hub/core/storage/local.py`
Content:
```
1 import os
2 import shutil
3 from typing import Optional, Set
4 
5 from hub.core.storage.provider import StorageProvider
6 from hub.util.exceptions import DirectoryAtPathException, FileAtPathException
7 
8 
9 class LocalProvider(StorageProvider):
10     """Provider class for using the local filesystem."""
11 
12     def __init__(self, root: str):
13         """Initializes the LocalProvider.
14 
15         Example:
16             local_provider = LocalProvider("/home/ubuntu/Documents/")
17 
18         Args:
19             root (str): The root of the provider. All read/write request keys will be appended to root."
20 
21         Raises:
22             FileAtPathException: If the root is a file instead of a directory.
23         """
24         if os.path.isfile(root):
25             raise FileAtPathException(root)
26         self.root = root
27         self.files: Optional[Set[str]] = None
28 
29     def subdir(self, path: str):
30         return self.__class__(os.path.join(self.root, path))
31 
32     def __getitem__(self, path: str):
33         """Gets the object present at the path within the given byte range.
34 
35         Example:
36             local_provider = LocalProvider("/home/ubuntu/Documents/")
37             my_data = local_provider["abc.txt"]
38 
39         Args:
40             path (str): The path relative to the root of the provider.
41 
42         Returns:
43             bytes: The bytes of the object present at the path.
44 
45         Raises:
46             KeyError: If an object is not found at the path.
47             DirectoryAtPathException: If a directory is found at the path.
48             Exception: Any other exception encountered while trying to fetch the object.
49         """
50         try:
51             full_path = self._check_is_file(path)
52             with open(full_path, "rb") as file:
53                 return file.read()
54         except DirectoryAtPathException:
55             raise
56         except FileNotFoundError:
57             raise KeyError(path)
58 
59     def __setitem__(self, path: str, value: bytes):
60         """Sets the object present at the path with the value
61 
62         Example:
63             local_provider = LocalProvider("/home/ubuntu/Documents/")
64             local_provider["abc.txt"] = b"abcd"
65 
66         Args:
67             path (str): the path relative to the root of the provider.
68             value (bytes): the value to be assigned at the path.
69 
70         Raises:
71             Exception: If unable to set item due to directory at path or permission or space issues.
72             FileAtPathException: If the directory to the path is a file instead of a directory.
73             ReadOnlyError: If the provider is in read-only mode.
74         """
75         self.check_readonly()
76         full_path = self._check_is_file(path)
77         directory = os.path.dirname(full_path)
78         if os.path.isfile(directory):
79             raise FileAtPathException(directory)
80         if not os.path.exists(directory):
81             os.makedirs(directory, exist_ok=True)
82         with open(full_path, "wb") as file:
83             file.write(value)
84         if self.files is not None:
85             self.files.add(path)
86 
87     def __delitem__(self, path: str):
88         """Delete the object present at the path.
89 
90         Example:
91             local_provider = LocalProvider("/home/ubuntu/Documents/")
92             del local_provider["abc.txt"]
93 
94         Args:
95             path (str): the path to the object relative to the root of the provider.
96 
97         Raises:
98             KeyError: If an object is not found at the path.
99             DirectoryAtPathException: If a directory is found at the path.
100             Exception: Any other exception encountered while trying to fetch the object.
101             ReadOnlyError: If the provider is in read-only mode.
102         """
103         self.check_readonly()
104         try:
105             full_path = self._check_is_file(path)
106             os.remove(full_path)
107             if self.files is not None:
108                 self.files.discard(path)
109         except DirectoryAtPathException:
110             raise
111         except FileNotFoundError:
112             raise KeyError
113 
114     def __iter__(self):
115         """Generator function that iterates over the keys of the provider.
116 
117         Example:
118             local_provider = LocalProvider("/home/ubuntu/Documents/")
119             for my_data in local_provider:
120                 pass
121 
122         Yields:
123             str: the path of the object that it is iterating over, relative to the root of the provider.
124         """
125         yield from self._all_keys()
126 
127     def __len__(self):
128         """Returns the number of files present inside the root of the provider.
129 
130         Example:
131             local_provider = LocalProvider("/home/ubuntu/Documents/")
132             len(local_provider)
133 
134         Returns:
135             int: the number of files present inside the root.
136         """
137         return len(self._all_keys())
138 
139     def _all_keys(self, refresh: bool = False) -> Set[str]:
140         """Lists all the objects present at the root of the Provider.
141 
142         Args:
143             refresh (bool): refresh keys
144 
145         Returns:
146             set: set of all the objects found at the root of the Provider.
147         """
148         if self.files is None or refresh:
149             full_path = os.path.expanduser(self.root)
150             key_set = set()
151             for root, dirs, files in os.walk(full_path):
152                 for file in files:
153                     key_set.add(
154                         os.path.relpath(os.path.join(full_path, file), full_path)
155                     )
156             self.files = key_set
157         return self.files
158 
159     def _check_is_file(self, path: str):
160         """Checks if the path is a file. Returns the full_path to file if True.
161 
162         Args:
163             path (str): the path to the object relative to the root of the provider.
164 
165         Returns:
166             str: the full path to the requested file.
167 
168         Raises:
169             DirectoryAtPathException: If a directory is found at the path.
170         """
171         full_path = os.path.join(self.root, path)
172         full_path = os.path.expanduser(full_path)
173         if os.path.isdir(full_path):
174             raise DirectoryAtPathException
175         return full_path
176 
177     def clear(self):
178         """Deletes ALL data on the local machine (under self.root). Exercise caution!"""
179         self.check_readonly()
180         self.files = set()
181         full_path = os.path.expanduser(self.root)
182         if os.path.exists(full_path):
183             shutil.rmtree(full_path)
184 
185     def __contains__(self, key) -> bool:
186         full_path = self._check_is_file(key)
187         return os.path.exists(full_path)
188
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/hub/core/storage/local.py b/hub/core/storage/local.py
--- a/hub/core/storage/local.py
+++ b/hub/core/storage/local.py
@@ -150,9 +150,7 @@
             key_set = set()
             for root, dirs, files in os.walk(full_path):
                 for file in files:
-                    key_set.add(
-                        os.path.relpath(os.path.join(full_path, file), full_path)
-                    )
+                    key_set.add(os.path.relpath(os.path.join(root, file), full_path))
             self.files = key_set
         return self.files

{"golden_diff": "diff --git a/hub/core/storage/local.py b/hub/core/storage/local.py\n--- a/hub/core/storage/local.py\n+++ b/hub/core/storage/local.py\n@@ -150,9 +150,7 @@\n             key_set = set()\n             for root, dirs, files in os.walk(full_path):\n                 for file in files:\n-                    key_set.add(\n-                        os.path.relpath(os.path.join(full_path, file), full_path)\n-                    )\n+                    key_set.add(os.path.relpath(os.path.join(root, file), full_path))\n             self.files = key_set\n         return self.files\n", "issue": "[BUG] dataset_meta.json isn't updated after create_tensor\n## \ud83d\udc1b\ud83d\udc1b Bug Report\r\n\r\nAfter loading an existing dataset with hub.dataset, create_tensor doesn't update the \"tensors\" attribute in dataset_meta.json.\r\n\r\n### \u2697\ufe0f Current Behavior\r\n\r\nFor example, a dataset called \"hub_dataset\" with tensor \"images\" already exists. Loading it with hub.dataset then appending a new tensor, \"test\":\r\n\r\n```python\r\nds = hub.dataset(\"hub_dataset\")\r\nds.create_tensor('test')\r\n```\r\nThe \"tensors\" attribute in dataset_meta.json won't contain the \"test\" tensor.\r\n\r\n```json\r\n{\"version\": \"2.0.8\", \"tensors\": [\"images\"]}\r\n```\r\n\r\n### \u2699\ufe0f Environment\r\n- `Python` version(s): [3.7.11]\r\n- `OS`: Ubuntu 18.04\n", "before_files": [{"content": "import os\nimport shutil\nfrom typing import Optional, Set\n\nfrom hub.core.storage.provider import StorageProvider\nfrom hub.util.exceptions import DirectoryAtPathException, FileAtPathException\n\n\nclass LocalProvider(StorageProvider):\n    \"\"\"Provider class for using the local filesystem.\"\"\"\n\n    def __init__(self, root: str):\n        \"\"\"Initializes the LocalProvider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n\n        Args:\n            root (str): The root of the provider. All read/write request keys will be appended to root.\"\n\n        Raises:\n            FileAtPathException: If the root is a file instead of a directory.\n        \"\"\"\n        if os.path.isfile(root):\n            raise FileAtPathException(root)\n        self.root = root\n        self.files: Optional[Set[str]] = None\n\n    def subdir(self, path: str):\n        return self.__class__(os.path.join(self.root, path))\n\n    def __getitem__(self, path: str):\n        \"\"\"Gets the object present at the path within the given byte range.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            my_data = local_provider[\"abc.txt\"]\n\n        Args:\n            path (str): The path relative to the root of the provider.\n\n        Returns:\n            bytes: The bytes of the object present at the path.\n\n        Raises:\n            KeyError: If an object is not found at the path.\n            DirectoryAtPathException: If a directory is found at the path.\n            Exception: Any other exception encountered while trying to fetch the object.\n        \"\"\"\n        try:\n            full_path = self._check_is_file(path)\n            with open(full_path, \"rb\") as file:\n                return file.read()\n        except DirectoryAtPathException:\n            raise\n        except FileNotFoundError:\n            raise KeyError(path)\n\n    def __setitem__(self, path: str, value: bytes):\n        \"\"\"Sets the object present at the path with the value\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            local_provider[\"abc.txt\"] = b\"abcd\"\n\n        Args:\n            path (str): the path relative to the root of the provider.\n            value (bytes): the value to be assigned at the path.\n\n        Raises:\n            Exception: If unable to set item due to directory at path or permission or space issues.\n            FileAtPathException: If the directory to the path is a file instead of a directory.\n            ReadOnlyError: If the provider is in read-only mode.\n        \"\"\"\n        self.check_readonly()\n        full_path = self._check_is_file(path)\n        directory = os.path.dirname(full_path)\n        if os.path.isfile(directory):\n            raise FileAtPathException(directory)\n        if not os.path.exists(directory):\n            os.makedirs(directory, exist_ok=True)\n        with open(full_path, \"wb\") as file:\n            file.write(value)\n        if self.files is not None:\n            self.files.add(path)\n\n    def __delitem__(self, path: str):\n        \"\"\"Delete the object present at the path.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            del local_provider[\"abc.txt\"]\n\n        Args:\n            path (str): the path to the object relative to the root of the provider.\n\n        Raises:\n            KeyError: If an object is not found at the path.\n            DirectoryAtPathException: If a directory is found at the path.\n            Exception: Any other exception encountered while trying to fetch the object.\n            ReadOnlyError: If the provider is in read-only mode.\n        \"\"\"\n        self.check_readonly()\n        try:\n            full_path = self._check_is_file(path)\n            os.remove(full_path)\n            if self.files is not None:\n                self.files.discard(path)\n        except DirectoryAtPathException:\n            raise\n        except FileNotFoundError:\n            raise KeyError\n\n    def __iter__(self):\n        \"\"\"Generator function that iterates over the keys of the provider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            for my_data in local_provider:\n                pass\n\n        Yields:\n            str: the path of the object that it is iterating over, relative to the root of the provider.\n        \"\"\"\n        yield from self._all_keys()\n\n    def __len__(self):\n        \"\"\"Returns the number of files present inside the root of the provider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            len(local_provider)\n\n        Returns:\n            int: the number of files present inside the root.\n        \"\"\"\n        return len(self._all_keys())\n\n    def _all_keys(self, refresh: bool = False) -> Set[str]:\n        \"\"\"Lists all the objects present at the root of the Provider.\n\n        Args:\n            refresh (bool): refresh keys\n\n        Returns:\n            set: set of all the objects found at the root of the Provider.\n        \"\"\"\n        if self.files is None or refresh:\n            full_path = os.path.expanduser(self.root)\n            key_set = set()\n            for root, dirs, files in os.walk(full_path):\n                for file in files:\n                    key_set.add(\n                        os.path.relpath(os.path.join(full_path, file), full_path)\n                    )\n            self.files = key_set\n        return self.files\n\n    def _check_is_file(self, path: str):\n        \"\"\"Checks if the path is a file. Returns the full_path to file if True.\n\n        Args:\n            path (str): the path to the object relative to the root of the provider.\n\n        Returns:\n            str: the full path to the requested file.\n\n        Raises:\n            DirectoryAtPathException: If a directory is found at the path.\n        \"\"\"\n        full_path = os.path.join(self.root, path)\n        full_path = os.path.expanduser(full_path)\n        if os.path.isdir(full_path):\n            raise DirectoryAtPathException\n        return full_path\n\n    def clear(self):\n        \"\"\"Deletes ALL data on the local machine (under self.root). Exercise caution!\"\"\"\n        self.check_readonly()\n        self.files = set()\n        full_path = os.path.expanduser(self.root)\n        if os.path.exists(full_path):\n            shutil.rmtree(full_path)\n\n    def __contains__(self, key) -> bool:\n        full_path = self._check_is_file(key)\n        return os.path.exists(full_path)\n", "path": "hub/core/storage/local.py"}], "after_files": [{"content": "import os\nimport shutil\nfrom typing import Optional, Set\n\nfrom hub.core.storage.provider import StorageProvider\nfrom hub.util.exceptions import DirectoryAtPathException, FileAtPathException\n\n\nclass LocalProvider(StorageProvider):\n    \"\"\"Provider class for using the local filesystem.\"\"\"\n\n    def __init__(self, root: str):\n        \"\"\"Initializes the LocalProvider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n\n        Args:\n            root (str): The root of the provider. All read/write request keys will be appended to root.\"\n\n        Raises:\n            FileAtPathException: If the root is a file instead of a directory.\n        \"\"\"\n        if os.path.isfile(root):\n            raise FileAtPathException(root)\n        self.root = root\n        self.files: Optional[Set[str]] = None\n\n    def subdir(self, path: str):\n        return self.__class__(os.path.join(self.root, path))\n\n    def __getitem__(self, path: str):\n        \"\"\"Gets the object present at the path within the given byte range.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            my_data = local_provider[\"abc.txt\"]\n\n        Args:\n            path (str): The path relative to the root of the provider.\n\n        Returns:\n            bytes: The bytes of the object present at the path.\n\n        Raises:\n            KeyError: If an object is not found at the path.\n            DirectoryAtPathException: If a directory is found at the path.\n            Exception: Any other exception encountered while trying to fetch the object.\n        \"\"\"\n        try:\n            full_path = self._check_is_file(path)\n            with open(full_path, \"rb\") as file:\n                return file.read()\n        except DirectoryAtPathException:\n            raise\n        except FileNotFoundError:\n            raise KeyError(path)\n\n    def __setitem__(self, path: str, value: bytes):\n        \"\"\"Sets the object present at the path with the value\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            local_provider[\"abc.txt\"] = b\"abcd\"\n\n        Args:\n            path (str): the path relative to the root of the provider.\n            value (bytes): the value to be assigned at the path.\n\n        Raises:\n            Exception: If unable to set item due to directory at path or permission or space issues.\n            FileAtPathException: If the directory to the path is a file instead of a directory.\n            ReadOnlyError: If the provider is in read-only mode.\n        \"\"\"\n        self.check_readonly()\n        full_path = self._check_is_file(path)\n        directory = os.path.dirname(full_path)\n        if os.path.isfile(directory):\n            raise FileAtPathException(directory)\n        if not os.path.exists(directory):\n            os.makedirs(directory, exist_ok=True)\n        with open(full_path, \"wb\") as file:\n            file.write(value)\n        if self.files is not None:\n            self.files.add(path)\n\n    def __delitem__(self, path: str):\n        \"\"\"Delete the object present at the path.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            del local_provider[\"abc.txt\"]\n\n        Args:\n            path (str): the path to the object relative to the root of the provider.\n\n        Raises:\n            KeyError: If an object is not found at the path.\n            DirectoryAtPathException: If a directory is found at the path.\n            Exception: Any other exception encountered while trying to fetch the object.\n            ReadOnlyError: If the provider is in read-only mode.\n        \"\"\"\n        self.check_readonly()\n        try:\n            full_path = self._check_is_file(path)\n            os.remove(full_path)\n            if self.files is not None:\n                self.files.discard(path)\n        except DirectoryAtPathException:\n            raise\n        except FileNotFoundError:\n            raise KeyError\n\n    def __iter__(self):\n        \"\"\"Generator function that iterates over the keys of the provider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            for my_data in local_provider:\n                pass\n\n        Yields:\n            str: the path of the object that it is iterating over, relative to the root of the provider.\n        \"\"\"\n        yield from self._all_keys()\n\n    def __len__(self):\n        \"\"\"Returns the number of files present inside the root of the provider.\n\n        Example:\n            local_provider = LocalProvider(\"/home/ubuntu/Documents/\")\n            len(local_provider)\n\n        Returns:\n            int: the number of files present inside the root.\n        \"\"\"\n        return len(self._all_keys())\n\n    def _all_keys(self, refresh: bool = False) -> Set[str]:\n        \"\"\"Lists all the objects present at the root of the Provider.\n\n        Args:\n            refresh (bool): refresh keys\n\n        Returns:\n            set: set of all the objects found at the root of the Provider.\n        \"\"\"\n        if self.files is None or refresh:\n            full_path = os.path.expanduser(self.root)\n            key_set = set()\n            for root, dirs, files in os.walk(full_path):\n                for file in files:\n                    key_set.add(os.path.relpath(os.path.join(root, file), full_path))\n            self.files = key_set\n        return self.files\n\n    def _check_is_file(self, path: str):\n        \"\"\"Checks if the path is a file. Returns the full_path to file if True.\n\n        Args:\n            path (str): the path to the object relative to the root of the provider.\n\n        Returns:\n            str: the full path to the requested file.\n\n        Raises:\n            DirectoryAtPathException: If a directory is found at the path.\n        \"\"\"\n        full_path = os.path.join(self.root, path)\n        full_path = os.path.expanduser(full_path)\n        if os.path.isdir(full_path):\n            raise DirectoryAtPathException\n        return full_path\n\n    def clear(self):\n        \"\"\"Deletes ALL data on the local machine (under self.root). Exercise caution!\"\"\"\n        self.check_readonly()\n        self.files = set()\n        full_path = os.path.expanduser(self.root)\n        if os.path.exists(full_path):\n            shutil.rmtree(full_path)\n\n    def __contains__(self, key) -> bool:\n        full_path = self._check_is_file(key)\n        return os.path.exists(full_path)\n", "path": "hub/core/storage/local.py"}]}