int _hash_drv_autoextend( hash_drv_map_t map, int extents, unsigned long last_extent_size) { struct _hash_drv_header header; struct _hash_drv_spam_record rec; int i, lastsize; _hash_drv_close(map); map->fd = open(map->filename, O_RDWR); if (map->fd < 0) { LOG(LOG_WARNING, "unable to resize hash. open failed: %s", strerror(errno)); return EFAILURE; } memset(&header, 0, sizeof(struct _hash_drv_header)); memset(&rec, 0, sizeof(struct _hash_drv_spam_record)); if (extents == 0 || !map->pctincrease) header.hash_rec_max = map->extent_size; else header.hash_rec_max = last_extent_size + (last_extent_size * (map->pctincrease/100.0)); LOGDEBUG("adding extent last: %d(%ld) new: %d(%ld) pctincrease: %1.2f", extents, last_extent_size, extents+1, header.hash_rec_max, (map->pctincrease/100.0)); lastsize=lseek (map->fd, 0, SEEK_END); if(write (map->fd, &header, sizeof(struct _hash_drv_header))!=sizeof(struct _hash_drv_header)) { ftruncate(map->fd,lastsize); close(map->fd); LOG(LOG_WARNING, "unable to resize hash. open failed: %s", strerror(errno)); return EFAILURE; } for(i=0;i<header.hash_rec_max;i++) if(write (map->fd, &rec, sizeof(struct _hash_drv_spam_record))!=sizeof(struct _hash_drv_spam_record)) { ftruncate(map->fd,lastsize); close(map->fd); LOG(LOG_WARNING, "unable to resize hash. open failed: %s", strerror(errno)); return EFAILURE; } close(map->fd); _hash_drv_open(map->filename, map, 0, map->max_seek, map->max_extents, map->extent_size, map->pctincrease, map->flags); return 0; }
int cssstat(const char *filename) { struct _hash_drv_map map; hash_drv_header_t header; hash_drv_spam_record_t rec; unsigned long filepos = sizeof(struct _hash_drv_header); unsigned long nfree = 0, nused = 0; unsigned long efree, eused; unsigned long extents = 0; unsigned long i; unsigned long hash_rec_max = HASH_REC_MAX; unsigned long max_seek = HASH_SEEK_MAX; unsigned long max_extents = 0; unsigned long extent_size = HASH_EXTENT_MAX; int flags = 0; if (READ_ATTRIB("HashRecMax")) hash_rec_max = strtol(READ_ATTRIB("HashRecMax"), NULL, 0); if (READ_ATTRIB("HashExtentSize")) extent_size = strtol(READ_ATTRIB("HashExtentSize"), NULL, 0); if (READ_ATTRIB("HashMaxExtents")) max_extents = strtol(READ_ATTRIB("HashMaxExtents"), NULL, 0); if (MATCH_ATTRIB("HashAutoExtend", "on")) flags = HMAP_AUTOEXTEND; if (READ_ATTRIB("HashMaxSeek")) max_seek = strtol(READ_ATTRIB("HashMaxSeek"), NULL, 0); if (_hash_drv_open(filename, &map, 0, max_seek, max_extents, extent_size, 0, flags)) { return EFAILURE; } header = map.addr; printf("filename %s length %ld\n", filename, (long) map.file_len); while(filepos < map.file_len) { printf("extent %lu: record length %lu\n", extents, (unsigned long) header->hash_rec_max); efree = eused = 0; for(i=0;i<header->hash_rec_max;i++) { rec = map.addr+filepos; if (rec->hashcode) { eused++; nused++; } else { efree++; nfree++; } filepos += sizeof(struct _hash_drv_spam_record); } header = map.addr + filepos; filepos += sizeof(struct _hash_drv_header); extents++; printf("\textent records used %lu\n", eused); printf("\textent records free %lu\n", efree); } _hash_drv_close(&map); printf("total database records used %lu\n", nused); printf("total database records free %lu\n", nfree); printf("total extents %lu\n", extents); return 0; }
int dspam_init_driver (DRIVER_CTX *DTX) { DSPAM_CTX *CTX; char *HashConcurrentUser; #ifdef DAEMON unsigned long connection_cache = 1; #endif if (DTX == NULL) return 0; CTX = DTX->CTX; HashConcurrentUser = READ_ATTRIB("HashConcurrentUser"); #ifdef DAEMON /* * Stateful concurrent hash databases are preloaded into memory and * shared using a reader-writer lock. At the present moment, only a single * user can be loaded into any instance of the daemon, so it is only useful * if you are running with a system-wide filtering user. */ if (DTX->flags & DRF_STATEFUL) { char filename[MAX_FILENAME_LENGTH]; hash_drv_map_t map; unsigned long hash_rec_max = HASH_REC_MAX; unsigned long max_seek = HASH_SEEK_MAX; unsigned long max_extents = 0; unsigned long extent_size = HASH_EXTENT_MAX; int pctincrease = 0; int flags = HMAP_AUTOEXTEND; int ret, i; if (READ_ATTRIB("HashConnectionCache") && !HashConcurrentUser) connection_cache = strtol(READ_ATTRIB("HashConnectionCache"), NULL, 0); DTX->connection_cache = connection_cache; if (READ_ATTRIB("HashRecMax")) hash_rec_max = strtol(READ_ATTRIB("HashRecMax"), NULL, 0); if (READ_ATTRIB("HashExtentSize")) extent_size = strtol(READ_ATTRIB("HashExtentSize"), NULL, 0); if (READ_ATTRIB("HashMaxExtents")) max_extents = strtol(READ_ATTRIB("HashMaxExtents"), NULL, 0); if (!MATCH_ATTRIB("HashAutoExtend", "on")) flags = 0; if (READ_ATTRIB("HashPctIncrease")) { pctincrease = atoi(READ_ATTRIB("HashPctIncrease")); if (pctincrease > 100) { LOG(LOG_ERR, "HashPctIncrease out of range; ignoring"); pctincrease = 0; } } if (READ_ATTRIB("HashMaxSeek")) max_seek = strtol(READ_ATTRIB("HashMaxSeek"), NULL, 0); /* Connection array (just one single connection for hash_drv) */ DTX->connections = calloc(1, sizeof(struct _ds_drv_connection *) * connection_cache); if (DTX->connections == NULL) goto memerr; /* Initialize Connections */ for(i=0;i<connection_cache;i++) { DTX->connections[i] = calloc(1, sizeof(struct _ds_drv_connection)); if (DTX->connections[i] == NULL) goto memerr; /* Our connection's storage structure */ if (HashConcurrentUser) { DTX->connections[i]->dbh = calloc(1, sizeof(struct _hash_drv_map)); if (DTX->connections[i]->dbh == NULL) goto memerr; pthread_rwlock_init(&DTX->connections[i]->rwlock, NULL); } else { DTX->connections[i]->dbh = NULL; pthread_mutex_init(&DTX->connections[i]->lock, NULL); } } /* Load concurrent database into resident memory */ if (HashConcurrentUser) { map = (hash_drv_map_t) DTX->connections[0]->dbh; /* Tell the server our connection lock will be reader/writer based */ if (!(DTX->flags & DRF_RWLOCK)) DTX->flags |= DRF_RWLOCK; _ds_userdir_path(filename, DTX->CTX->home, HashConcurrentUser, "css"); _ds_prepare_path_for(filename); LOGDEBUG("preloading %s into memory via mmap()", filename); ret = _hash_drv_open(filename, map, hash_rec_max, max_seek, max_extents, extent_size, pctincrease, flags); if (ret) { LOG(LOG_CRIT, "_hash_drv_open(%s) failed on error %d: %s", filename, ret, strerror(errno)); free(DTX->connections[0]->dbh); free(DTX->connections[0]); free(DTX->connections); return EFAILURE; } } } #endif return 0; #ifdef DAEMON memerr: if (DTX) { if (DTX->connections) { int i; for(i=0;i<connection_cache;i++) { if (DTX->connections[i]) free(DTX->connections[i]->dbh); free(DTX->connections[i]); } } free(DTX->connections); } LOG(LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; #endif }
int _ds_init_storage (DSPAM_CTX * CTX, void *dbh) { struct _hash_drv_storage *s = NULL; hash_drv_map_t map = NULL; int ret; if (CTX == NULL) return EINVAL; if (!CTX->home) { LOG(LOG_ERR, ERR_AGENT_DSPAM_HOME); return EINVAL; } if (CTX->flags & DSF_MERGED) { LOG(LOG_ERR, ERR_DRV_NO_MERGED); return EINVAL; } if (CTX->storage) return EINVAL; /* Persistent driver storage */ s = calloc (1, sizeof (struct _hash_drv_storage)); if (s == NULL) { LOG(LOG_CRIT, ERR_MEM_ALLOC); return EUNKNOWN; } /* If running in HashConcurrentUser mode, use existing hash mapping */ if (dbh) { map = dbh; s->dbh_attached = 1; } else { map = calloc(1, sizeof(struct _hash_drv_map)); if (!map) { LOG(LOG_CRIT, ERR_MEM_ALLOC); free(s); return EUNKNOWN; } s->dbh_attached = 0; } s->map = map; /* Mapping defaults */ s->hash_rec_max = HASH_REC_MAX; s->max_seek = HASH_SEEK_MAX; s->max_extents = 0; s->extent_size = HASH_EXTENT_MAX; s->pctincrease = 0; s->flags = HMAP_AUTOEXTEND; if (READ_ATTRIB("HashRecMax")) s->hash_rec_max = strtol(READ_ATTRIB("HashRecMax"), NULL, 0); if (READ_ATTRIB("HashExtentSize")) s->extent_size = strtol(READ_ATTRIB("HashExtentSize"), NULL, 0); if (READ_ATTRIB("HashMaxExtents")) s->max_extents = strtol(READ_ATTRIB("HashMaxExtents"), NULL, 0); if (!MATCH_ATTRIB("HashAutoExtend", "on")) s->flags = 0; if (READ_ATTRIB("HashPctIncrease")) { s->pctincrease = atoi(READ_ATTRIB("HashPctIncrease")); if (s->pctincrease > 100) { LOG(LOG_ERR, "HashPctIncrease out of range; ignoring"); s->pctincrease = 0; } } if (READ_ATTRIB("HashMaxSeek")) s->max_seek = strtol(READ_ATTRIB("HashMaxSeek"), NULL, 0); if (!dbh && CTX->username != NULL) { char db[MAX_FILENAME_LENGTH]; int lock_result; if (CTX->group == NULL) _ds_userdir_path(db, CTX->home, CTX->username, "css"); else _ds_userdir_path(db, CTX->home, CTX->group, "css"); lock_result = _hash_drv_lock_get (CTX, s, (CTX->group) ? CTX->group : CTX->username); if (lock_result < 0) goto BAIL; ret = _hash_drv_open(db, s->map, s->hash_rec_max, s->max_seek, s->max_extents, s->extent_size, s->pctincrease, s->flags); if (ret) { _hash_drv_close(s->map); free(s); return EFAILURE; } } CTX->storage = s; s->dir_handles = nt_create (NT_INDEX); if (_hash_drv_get_spamtotals (CTX)) { LOGDEBUG ("unable to load totals. using zero values."); memset (&CTX->totals, 0, sizeof (struct _ds_spam_totals)); } return 0; BAIL: free(s); return EFAILURE; }