Load a Redis object of the specified type from the specified file. * On success a newly allocated object is returned, otherwise NULL. * When the function returns NULL and if 'error' is not NULL, the * integer pointed by 'error' is set to the type of error that occurred */
| 1784 | * When the function returns NULL and if 'error' is not NULL, the |
| 1785 | * integer pointed by 'error' is set to the type of error that occurred */ |
| 1786 | robj *rdbLoadObject(int rdbtype, rio *rdb, sds key, int *error, uint64_t mvcc_tstamp) { |
| 1787 | robj *o = NULL, *ele, *dec; |
| 1788 | uint64_t len; |
| 1789 | unsigned int i; |
| 1790 | |
| 1791 | /* Set default error of load object, it will be set to 0 on success. */ |
| 1792 | if (error) *error = RDB_LOAD_ERR_OTHER; |
| 1793 | |
| 1794 | int deep_integrity_validation = cserver.sanitize_dump_payload == SANITIZE_DUMP_YES; |
| 1795 | if (cserver.sanitize_dump_payload == SANITIZE_DUMP_CLIENTS) { |
| 1796 | /* Skip sanitization when loading (an RDB), or getting a RESTORE command |
| 1797 | * from either the master or a client using an ACL user with the skip-sanitize-payload flag. */ |
| 1798 | int skip = g_pserver->loading || |
| 1799 | (serverTL->current_client && (serverTL->current_client->flags & CLIENT_MASTER)); |
| 1800 | if (!skip && serverTL->current_client && serverTL->current_client->user) |
| 1801 | skip = !!(serverTL->current_client->user->flags & USER_FLAG_SANITIZE_PAYLOAD_SKIP); |
| 1802 | deep_integrity_validation = !skip; |
| 1803 | } |
| 1804 | |
| 1805 | if (rdbtype == RDB_TYPE_STRING) { |
| 1806 | /* Read string value */ |
| 1807 | if ((o = rdbLoadEncodedStringObject(rdb)) == NULL) return NULL; |
| 1808 | o = tryObjectEncoding(o); |
| 1809 | } else if (rdbtype == RDB_TYPE_LIST) { |
| 1810 | /* Read list value */ |
| 1811 | if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL; |
| 1812 | if (len == 0) goto emptykey; |
| 1813 | |
| 1814 | o = createQuicklistObject(); |
| 1815 | quicklistSetOptions((quicklist*)ptrFromObj(o), g_pserver->list_max_ziplist_size, |
| 1816 | g_pserver->list_compress_depth); |
| 1817 | |
| 1818 | /* Load every single element of the list */ |
| 1819 | while(len--) { |
| 1820 | if ((ele = rdbLoadEncodedStringObject(rdb)) == NULL) { |
| 1821 | decrRefCount(o); |
| 1822 | return NULL; |
| 1823 | } |
| 1824 | dec = getDecodedObject(ele); |
| 1825 | size_t len = sdslen(szFromObj(dec)); |
| 1826 | quicklistPushTail((quicklist*)ptrFromObj(o), ptrFromObj(dec), len); |
| 1827 | decrRefCount(dec); |
| 1828 | decrRefCount(ele); |
| 1829 | } |
| 1830 | } else if (rdbtype == RDB_TYPE_SET) { |
| 1831 | /* Read Set value */ |
| 1832 | if ((len = rdbLoadLen(rdb,NULL)) == RDB_LENERR) return NULL; |
| 1833 | if (len == 0) goto emptykey; |
| 1834 | |
| 1835 | /* Use a regular set when there are too many entries. */ |
| 1836 | size_t max_entries = g_pserver->set_max_intset_entries; |
| 1837 | if (max_entries >= 1<<30) max_entries = 1<<30; |
| 1838 | if (len > max_entries) { |
| 1839 | o = createSetObject(); |
| 1840 | /* It's faster to expand the dict to the right size asap in order |
| 1841 | * to avoid rehashing */ |
| 1842 | if (len > DICT_HT_INITIAL_SIZE && dictTryExpand((dict*)ptrFromObj(o),len,false) != DICT_OK) { |
| 1843 | rdbReportCorruptRDB("OOM in dictTryExpand %llu", (unsigned long long)len); |
no test coverage detected