+ memcpy(&zheader, cdb->ptr, cplen);
+
+ compressed_data = cdb->ptr;
+ compressed_data += sizeof(struct CtdlCompressHeader);
+
+ sourceLen = (uLongf) zheader.compressed_len;
+ destLen = (uLongf) zheader.uncompressed_len;
+ uncompressed_data = malloc(zheader.uncompressed_len);
+
+ if (uncompress((Bytef *) uncompressed_data,
+ (uLongf *) & destLen, (const Bytef *) compressed_data, (uLong) sourceLen) != Z_OK) {
+ syslog(LOG_EMERG, "db: uncompress() error");
+ cdb_abort();
+ }
+
+ free(cdb->ptr);
+ cdb->len = (size_t) destLen;
+ cdb->ptr = uncompressed_data;
+}
+
+
+/*
+ * Store a piece of data. Returns 0 if the operation was successful. If a
+ * key already exists it should be overwritten.
+ */
+int cdb_store(int cdb, const void *ckey, int ckeylen, void *cdata, int cdatalen)
+{
+
+ DBT dkey, ddata;
+ DB_TXN *tid;
+ int ret = 0;
+
+ struct CtdlCompressHeader zheader;
+ char *compressed_data = NULL;
+ int compressing = 0;
+ size_t buffer_len = 0;
+ uLongf destLen = 0;
+
+ memset(&dkey, 0, sizeof(DBT));
+ memset(&ddata, 0, sizeof(DBT));
+ dkey.size = ckeylen;
+ dkey.data = (void *) ckey;
+ ddata.size = cdatalen;
+ ddata.data = cdata;
+
+ /* Only compress Visit and UseTable records. Everything else is uncompressed. */
+ if ((cdb == CDB_VISIT) || (cdb == CDB_USETABLE)) {
+ compressing = 1;
+ zheader.magic = COMPRESS_MAGIC;
+ zheader.uncompressed_len = cdatalen;
+ buffer_len = ((cdatalen * 101) / 100) + 100 + sizeof(struct CtdlCompressHeader);
+ destLen = (uLongf) buffer_len;
+ compressed_data = malloc(buffer_len);
+ if (compress2((Bytef *) (compressed_data + sizeof(struct CtdlCompressHeader)),
+ &destLen, (Bytef *) cdata, (uLongf) cdatalen, 1) != Z_OK) {
+ syslog(LOG_EMERG, "db: compress2() error");
+ cdb_abort();
+ }
+ zheader.compressed_len = (size_t) destLen;
+ memcpy(compressed_data, &zheader, sizeof(struct CtdlCompressHeader));
+ ddata.size = (size_t) (sizeof(struct CtdlCompressHeader) + zheader.compressed_len);
+ ddata.data = compressed_data;
+ }
+
+ if (TSD->tid != NULL) {
+ ret = dbp[cdb]->put(dbp[cdb], // db
+ TSD->tid, // transaction ID
+ &dkey, // key
+ &ddata, // data
+ 0 // flags
+ );
+ if (ret) {
+ syslog(LOG_EMERG, "db: cdb_store(%d): %s", cdb, db_strerror(ret));
+ cdb_abort();
+ }
+ if (compressing) {
+ free(compressed_data);
+ }
+ return ret;
+ } else {
+ bailIfCursor(TSD->cursors, "attempt to write during r/o cursor");
+
+ retry:
+ txbegin(&tid);
+
+ if ((ret = dbp[cdb]->put(dbp[cdb], /* db */
+ tid, /* transaction ID */
+ &dkey, /* key */
+ &ddata, /* data */
+ 0))) { /* flags */
+ if (ret == DB_LOCK_DEADLOCK) {
+ txabort(tid);
+ goto retry;
+ } else {
+ syslog(LOG_EMERG, "db: cdb_store(%d): %s", cdb, db_strerror(ret));
+ cdb_abort();
+ }
+ } else {
+ txcommit(tid);
+ if (compressing) {
+ free(compressed_data);
+ }
+ return ret;
+ }
+ }
+ return ret;