View | Details | Raw Unified | Return to bug 39380
Collapse All | Expand All

(-)mod_disk_cache.c.1-lfsconfig (-41 / +263 lines)
Lines 157-163 static apr_status_t file_cache_el_final( Link Here
157
    if (dobj->tfd) {
157
    if (dobj->tfd) {
158
        apr_status_t rv;
158
        apr_status_t rv;
159
159
160
        apr_file_close(dobj->tfd);
160
        rv = apr_file_close(dobj->tfd);
161
        dobj->tfd = NULL;
162
163
        if(rv != APR_SUCCESS) {
164
            ap_log_error(APLOG_MARK, APLOG_DEBUG, rv, r->server,
165
                         "disk_cache: closing tempfile failed: %s",
166
                         dobj->tempfile);
167
            apr_file_remove(dobj->tempfile, r->pool);
168
            return rv;
169
        }
161
170
162
        /* This assumes that the tempfile is on the same file system
171
        /* This assumes that the tempfile is on the same file system
163
         * as the cache_root. If not, then we need a file copy/move
172
         * as the cache_root. If not, then we need a file copy/move
Lines 169-177 static apr_status_t file_cache_el_final( Link Here
169
                         "disk_cache: rename tempfile to datafile failed:"
178
                         "disk_cache: rename tempfile to datafile failed:"
170
                         " %s -> %s", dobj->tempfile, dobj->datafile);
179
                         " %s -> %s", dobj->tempfile, dobj->datafile);
171
            apr_file_remove(dobj->tempfile, r->pool);
180
            apr_file_remove(dobj->tempfile, r->pool);
181
            return rv;
172
        }
182
        }
173
174
        dobj->tfd = NULL;
175
    }
183
    }
176
184
177
    return APR_SUCCESS;
185
    return APR_SUCCESS;
Lines 976-990 static apr_status_t store_headers(cache_ Link Here
976
    return APR_SUCCESS;
984
    return APR_SUCCESS;
977
}
985
}
978
986
987
988
static apr_status_t copy_body(apr_file_t *srcfd, apr_off_t srcoff, 
989
                              apr_file_t *destfd, apr_off_t destoff, 
990
                              apr_off_t len)
991
{
992
    apr_status_t rc;
993
    apr_size_t size;
994
    apr_finfo_t finfo;
995
    apr_time_t starttime = apr_time_now();
996
    char buf[CACHE_BUF_SIZE];
997
998
    if(srcoff != 0) {
999
        rc = apr_file_seek(srcfd, APR_SET, &srcoff);
1000
        if(rc != APR_SUCCESS) {
1001
            return rc;
1002
        }
1003
    }
1004
1005
    if(destoff != 0) {
1006
        rc = apr_file_seek(destfd, APR_SET, &destoff);
1007
        if(rc != APR_SUCCESS) {
1008
            return rc;
1009
        }
1010
    }
1011
1012
    /* Tried doing this with mmap, but sendfile on Linux got confused when
1013
       sending a file while it was being written to from an mmapped area.
1014
       The traditional way seems to be good enough, and less complex.
1015
     */
1016
    while(len > 0) {
1017
        size=MIN(len, CACHE_BUF_SIZE);
1018
1019
        rc = apr_file_read_full (srcfd, buf, size, NULL);
1020
        if(rc != APR_SUCCESS) {
1021
            return rc;
1022
        }
1023
1024
        rc = apr_file_write_full(destfd, buf, size, NULL);
1025
        if(rc != APR_SUCCESS) {
1026
            return rc;
1027
        }
1028
        len -= size;
1029
    }
1030
1031
    /* Check if file has changed during copying. This is not 100% foolproof
1032
       due to NFS attribute caching when on NFS etc. */
1033
    /* FIXME: Can we assume that we're always copying an entire file? In that
1034
              case we can check if the current filesize matches the length
1035
              we think it is */
1036
    rc = apr_file_info_get(&finfo, APR_FINFO_MTIME, srcfd);
1037
    if(rc != APR_SUCCESS) {
1038
        return rc;
1039
    }
1040
    if(starttime < finfo.mtime) {
1041
        return APR_EGENERAL;
1042
    }
1043
1044
    return APR_SUCCESS;
1045
}
1046
1047
1048
static apr_status_t replace_brigade_with_cache(cache_handle_t *h,
1049
                                               request_rec *r,
1050
                                               apr_bucket_brigade *bb)
1051
{
1052
    apr_status_t rv;
1053
    int flags;
1054
    apr_bucket *e;
1055
    core_dir_config *pdcfg = ap_get_module_config(r->per_dir_config,
1056
            &core_module);
1057
    disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
1058
1059
    flags = APR_READ|APR_BINARY;
1060
#if APR_HAS_SENDFILE
1061
    flags |= ((pdcfg->enable_sendfile == ENABLE_SENDFILE_OFF)
1062
            ? 0 : APR_SENDFILE_ENABLED);
1063
#endif
1064
1065
    rv = apr_file_open(&dobj->fd, dobj->datafile, flags, 0, r->pool);
1066
    if (rv != APR_SUCCESS) {
1067
        ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
1068
                     "disk_cache: Error opening datafile %s for URL %s",
1069
                     dobj->datafile, dobj->name);
1070
        return rv;
1071
    }
1072
1073
    /* First, empty the brigade */
1074
    e  = APR_BRIGADE_FIRST(bb);
1075
    while (e != APR_BRIGADE_SENTINEL(bb)) {
1076
        apr_bucket *d;
1077
        d = e;
1078
        e = APR_BUCKET_NEXT(e);
1079
        apr_bucket_delete(d);
1080
    }
1081
1082
    /* Then, populate it with our cached instance */
1083
    rv = recall_body(h, r->pool, bb);
1084
    if (rv != APR_SUCCESS) {
1085
        ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
1086
                     "disk_cache: Error serving URL %s from cache", dobj->name);
1087
        return rv;
1088
    }
1089
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1090
                 "disk_cache: Serving cached body for URL %s", dobj->name);
1091
1092
    return APR_SUCCESS;
1093
}
1094
1095
979
static apr_status_t store_body(cache_handle_t *h, request_rec *r,
1096
static apr_status_t store_body(cache_handle_t *h, request_rec *r,
980
                               apr_bucket_brigade *bb)
1097
                               apr_bucket_brigade *bb)
981
{
1098
{
982
    apr_bucket *e;
1099
    apr_bucket *e;
983
    apr_status_t rv;
1100
    apr_status_t rv;
1101
    int copy_file = FALSE;
984
    disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
1102
    disk_cache_object_t *dobj = (disk_cache_object_t *) h->cache_obj->vobj;
985
    disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
1103
    disk_cache_conf *conf = ap_get_module_config(r->server->module_config,
986
                                                 &disk_cache_module);
1104
                                                 &disk_cache_module);
987
1105
1106
    if(r->no_cache) {
1107
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1108
                     "disk_cache: store_body called for URL %s even though"
1109
                     "no_cache is set", dobj->name);
1110
        file_cache_errorcleanup(dobj, r);
1111
        return APR_EGENERAL;
1112
    }
1113
988
    /* We write to a temp file and then atomically rename the file over
1114
    /* We write to a temp file and then atomically rename the file over
989
     * in file_cache_el_final().
1115
     * in file_cache_el_final().
990
     */
1116
     */
Lines 998-1044 static apr_status_t store_body(cache_han Link Here
998
        dobj->file_size = 0;
1124
        dobj->file_size = 0;
999
    }
1125
    }
1000
1126
1001
    for (e = APR_BRIGADE_FIRST(bb);
1127
    /* Check if this is a complete single sequential file, eligable for
1002
         e != APR_BRIGADE_SENTINEL(bb);
1128
     * file copy.
1003
         e = APR_BUCKET_NEXT(e))
1129
     */
1130
    if(dobj->file_size == 0 && APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb)))
1004
    {
1131
    {
1005
        const char *str;
1132
        apr_off_t begin = -1;
1006
        apr_size_t length, written;
1133
        apr_off_t pos = -1;
1007
        rv = apr_bucket_read(e, &str, &length, APR_BLOCK_READ);
1134
        apr_file_t *fd = NULL;
1008
        if (rv != APR_SUCCESS) {
1135
        apr_bucket_file *a;
1009
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
1136
1010
                         "disk_cache: Error when reading bucket for URL %s",
1137
        copy_file = TRUE;
1011
                         h->cache_obj->key);
1138
1012
            /* Remove the intermediate cache file and return non-APR_SUCCESS */
1139
        for (e = APR_BRIGADE_FIRST(bb);
1013
            file_cache_errorcleanup(dobj, r);
1140
                e != APR_BRIGADE_SENTINEL(bb);
1014
            return rv;
1141
                e = APR_BUCKET_NEXT(e))
1142
        {
1143
            if(APR_BUCKET_IS_EOS(e)) {
1144
                break;
1145
            }
1146
            if(!APR_BUCKET_IS_FILE(e)) {
1147
                copy_file = FALSE;
1148
                break;
1149
            }
1150
1151
            a = e->data;
1152
1153
            if(begin < 0) {
1154
                begin = pos = e->start;
1155
                fd = a->fd;
1156
            }
1157
1158
            if(fd != a->fd || pos != e->start) {
1159
                copy_file = FALSE;
1160
                break;
1161
            }
1162
1163
            pos += e->length;
1015
        }
1164
        }
1016
        rv = apr_file_write_full(dobj->tfd, str, length, &written);
1165
1017
        if (rv != APR_SUCCESS) {
1166
        if(copy_file) {
1018
            ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
1167
            dobj->file_size = pos;
1019
                         "disk_cache: Error when writing cache file for URL %s",
1168
        }
1020
                         h->cache_obj->key);
1169
    }
1021
            /* Remove the intermediate cache file and return non-APR_SUCCESS */
1170
1171
    if(copy_file) {
1172
        apr_bucket_file *a;
1173
1174
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
1175
                     "disk_cache: Copying body for URL %s, len %"
1176
                     APR_OFF_T_FMT, dobj->name, dobj->file_size);
1177
1178
        e = APR_BRIGADE_FIRST(bb);
1179
        a = e->data;
1180
1181
        rv = copy_body(a->fd, e->start, dobj->tfd, 0, 
1182
                       dobj->file_size);
1183
        if(rv != APR_SUCCESS) {
1184
            ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
1185
                         "disk_cache: Copying body failed, "
1186
                         "URL %s", dobj->name);
1022
            file_cache_errorcleanup(dobj, r);
1187
            file_cache_errorcleanup(dobj, r);
1023
            return rv;
1188
            return rv;
1024
        }
1189
        }
1025
        dobj->file_size += written;
1190
1026
        if (dobj->file_size > conf->maxfs) {
1191
    }
1027
            ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1192
    else {
1028
                         "disk_cache: URL %s failed the size check "
1193
        ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
1029
                         "(%" APR_OFF_T_FMT ">%" APR_OFF_T_FMT ")",
1194
                     "disk_cache: Caching body for URL %s", dobj->name);
1030
                         h->cache_obj->key, dobj->file_size, conf->maxfs);
1195
1031
            /* Remove the intermediate cache file and return non-APR_SUCCESS */
1196
        for (e = APR_BRIGADE_FIRST(bb);
1032
            file_cache_errorcleanup(dobj, r);
1197
                e != APR_BRIGADE_SENTINEL(bb);
1033
            return APR_EGENERAL;
1198
                e = APR_BUCKET_NEXT(e))
1199
        {   
1200
            const char *str;
1201
            apr_size_t length, written;
1202
1203
            /* Ignore the non-data-buckets */
1204
            if(APR_BUCKET_IS_METADATA(e)) {
1205
                continue;
1206
            }
1207
1208
            rv = apr_bucket_read(e, &str, &length, APR_BLOCK_READ);
1209
            if (rv != APR_SUCCESS) {
1210
                ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
1211
                             "disk_cache: Error when reading bucket for URL %s",
1212
                             dobj->name);
1213
                file_cache_errorcleanup(dobj, r);
1214
                return rv;
1215
            }
1216
            rv = apr_file_write_full(dobj->fd, str, length, &written);
1217
            if (rv != APR_SUCCESS) {
1218
                ap_log_error(APLOG_MARK, APLOG_ERR, rv, r->server,
1219
                             "disk_cache: Error when writing cache file for "
1220
                             "URL %s", dobj->name);
1221
                file_cache_errorcleanup(dobj, r);
1222
                return rv;
1223
            }
1224
            dobj->file_size += written;
1225
            if (dobj->file_size > conf->maxfs) {
1226
                ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1227
                             "disk_cache: URL %s failed the size check "
1228
                             "(%" APR_OFF_T_FMT " > %" APR_OFF_T_FMT ")",
1229
                             dobj->name, dobj->file_size, conf->maxfs);
1230
                file_cache_errorcleanup(dobj, r);
1231
                return APR_EGENERAL;
1232
            }
1034
        }
1233
        }
1035
    }
1234
    }
1036
1235
1037
    /* Was this the final bucket? If yes, close the temp file and perform
1236
1038
     * sanity checks.
1237
    /* Drop out here if this wasn't the end */
1039
     */
1238
    if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
1040
    if (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb))) {
1239
        return APR_SUCCESS;
1041
        if (r->connection->aborted || r->no_cache) {
1240
    }
1241
1242
    if(!copy_file) {
1243
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1244
                     "disk_cache: Done caching URL %s, len %" APR_OFF_T_FMT,
1245
                     dobj->name, dobj->file_size);
1246
1247
        /* FIXME: Do we really need to check r->no_cache here since we checked
1248
           it in the beginning? */
1249
        if (r->no_cache || r->connection->aborted) {
1042
            ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
1250
            ap_log_error(APLOG_MARK, APLOG_INFO, 0, r->server,
1043
                         "disk_cache: Discarding body for URL %s "
1251
                         "disk_cache: Discarding body for URL %s "
1044
                         "because connection has been aborted.",
1252
                         "because connection has been aborted.",
Lines 1056-1072 static apr_status_t store_body(cache_han Link Here
1056
            file_cache_errorcleanup(dobj, r);
1264
            file_cache_errorcleanup(dobj, r);
1057
            return APR_EGENERAL;
1265
            return APR_EGENERAL;
1058
        }
1266
        }
1267
    }
1059
1268
1060
        /* All checks were fine. Move tempfile to final destination */
1269
    /* All checks were fine. Move tempfile to final destination */
1061
        /* Link to the perm file, and close the descriptor */
1270
    /* Link to the perm file, and close the descriptor */
1062
        file_cache_el_final(dobj, r);
1271
    rv = file_cache_el_final(dobj, r);
1063
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1272
    if(rv != APR_SUCCESS) {
1064
                     "disk_cache: Body for URL %s cached.",  dobj->name);
1273
        file_cache_errorcleanup(dobj, r);
1274
        return rv;
1275
    }
1276
1277
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
1278
                 "disk_cache: Body for URL %s cached.",  dobj->name);
1279
1280
    /* Redirect to cachefile if we copied a plain file */
1281
    if(copy_file) {
1282
        rv = replace_brigade_with_cache(h, r, bb);
1283
        if(rv != APR_SUCCESS) {
1284
            return rv;
1285
        }
1065
    }
1286
    }
1066
1287
1067
    return APR_SUCCESS;
1288
    return APR_SUCCESS;
1068
}
1289
}
1069
1290
1291
1070
static void *create_config(apr_pool_t *p, server_rec *s)
1292
static void *create_config(apr_pool_t *p, server_rec *s)
1071
{
1293
{
1072
    disk_cache_conf *conf = apr_pcalloc(p, sizeof(disk_cache_conf));
1294
    disk_cache_conf *conf = apr_pcalloc(p, sizeof(disk_cache_conf));
(-)mod_disk_cache.h.1-lfsconfig (+2 lines)
Lines 28-33 Link Here
28
#define CACHE_DATA_SUFFIX   ".data"
28
#define CACHE_DATA_SUFFIX   ".data"
29
#define CACHE_VDIR_SUFFIX   ".vary"
29
#define CACHE_VDIR_SUFFIX   ".vary"
30
30
31
#define CACHE_BUF_SIZE 65536
32
31
#define AP_TEMPFILE_PREFIX "/"
33
#define AP_TEMPFILE_PREFIX "/"
32
#define AP_TEMPFILE_BASE   "aptmp"
34
#define AP_TEMPFILE_BASE   "aptmp"
33
#define AP_TEMPFILE_SUFFIX "XXXXXX"
35
#define AP_TEMPFILE_SUFFIX "XXXXXX"

Return to bug 39380