Revision b90584d0

b/snf-pithos-app/pithos/api/functions.py
971 971
    return object_data_response(request, sizes, hashmaps, meta)
972 972

  
973 973

  
974
@api_method('PUT', format_allowed=True, user_required=True, logger=logger)
974
@api_method('PUT', format_allowed=True, user_required=True, logger=logger,
975
            lock_container_path=True)
975 976
def object_write(request, v_account, v_container, v_object):
976 977
    # Normal Response Codes: 201
977 978
    # Error Response Codes: internalServerError (500),
......
983 984
    #                       badRequest (400)
984 985
    #                       requestentitytoolarge (413)
985 986

  
986
    # lock container path for concurrent updates
987
    request.backend.lock_path('/'.join([v_account, v_container]))
988

  
989 987
    # Evaluate conditions.
990 988
    if (request.META.get('HTTP_IF_MATCH')
991 989
            or request.META.get('HTTP_IF_NONE_MATCH')):
......
1146 1144
    return response
1147 1145

  
1148 1146

  
1149
@api_method('POST', user_required=True, logger=logger)
1147
@api_method('POST', user_required=True, logger=logger, lock_container_path=True)
1150 1148
def object_write_form(request, v_account, v_container, v_object):
1151 1149
    # Normal Response Codes: 201
1152 1150
    # Error Response Codes: internalServerError (500),
......
1160 1158
        raise faults.BadRequest('Missing X-Object-Data field')
1161 1159
    file = request.FILES['X-Object-Data']
1162 1160

  
1163
    # lock container path for concurrent updates
1164
    request.backend.lock_path('/'.join([v_account, v_container]))
1165

  
1166 1161
    checksum = file.etag
1167 1162
    try:
1168 1163
        version_id = \
......
1186 1181
    return response
1187 1182

  
1188 1183

  
1189
@api_method('COPY', format_allowed=True, user_required=True, logger=logger)
1184
@api_method('COPY', format_allowed=True, user_required=True, logger=logger,
1185
            lock_container_path=True)
1190 1186
def object_copy(request, v_account, v_container, v_object):
1191 1187
    # Normal Response Codes: 201
1192 1188
    # Error Response Codes: internalServerError (500),
......
1206 1202
    except ValueError:
1207 1203
        raise faults.BadRequest('Invalid Destination header')
1208 1204

  
1209
    # lock container path for concurrent updates
1210
    request.backend.lock_path('/'.join([v_account, v_container]))
1211

  
1212 1205
    # Evaluate conditions.
1213 1206
    if (request.META.get('HTTP_IF_MATCH')
1214 1207
            or request.META.get('HTTP_IF_NONE_MATCH')):
......
1233 1226
    return response
1234 1227

  
1235 1228

  
1236
@api_method('MOVE', format_allowed=True, user_required=True, logger=logger)
1229
@api_method('MOVE', format_allowed=True, user_required=True, logger=logger,
1230
            lock_container_path=True)
1237 1231
def object_move(request, v_account, v_container, v_object):
1238 1232
    # Normal Response Codes: 201
1239 1233
    # Error Response Codes: internalServerError (500),
......
1253 1247
    except ValueError:
1254 1248
        raise faults.BadRequest('Invalid Destination header')
1255 1249

  
1256
    # lock container path for concurrent updates
1257
    request.backend.lock_path('/'.join([v_account, v_container]))
1258

  
1259 1250
    # Evaluate conditions.
1260 1251
    if (request.META.get('HTTP_IF_MATCH')
1261 1252
            or request.META.get('HTTP_IF_NONE_MATCH')):
......
1279 1270
    return response
1280 1271

  
1281 1272

  
1282
@api_method('POST', format_allowed=True, user_required=True, logger=logger)
1273
@api_method('POST', format_allowed=True, user_required=True, logger=logger,
1274
            lock_container_path=True)
1283 1275
def object_update(request, v_account, v_container, v_object):
1284 1276
    # Normal Response Codes: 202, 204
1285 1277
    # Error Response Codes: internalServerError (500),
......
1290 1282

  
1291 1283
    content_type, meta, permissions, public = get_object_headers(request)
1292 1284

  
1293
    # lock container path for concurrent updates
1294
    request.backend.lock_path('/'.join([v_account, v_container]))
1295

  
1296 1285
    try:
1297 1286
        prev_meta = request.backend.get_object_meta(
1298 1287
            request.user_uniq, v_account,
......
1507 1496
    return response
1508 1497

  
1509 1498

  
1510
@api_method('DELETE', user_required=True, logger=logger)
1499
@api_method('DELETE', user_required=True, logger=logger,
1500
            lock_container_path=True)
1511 1501
def object_delete(request, v_account, v_container, v_object):
1512 1502
    # Normal Response Codes: 204
1513 1503
    # Error Response Codes: internalServerError (500),
......
1519 1509
    until = get_int_parameter(request.GET.get('until'))
1520 1510
    delimiter = request.GET.get('delimiter')
1521 1511

  
1522
    # lock container path for concurrent updates
1523
    request.backend.lock_path('/'.join([v_account, v_container]))
1524

  
1525 1512
    try:
1526 1513
        request.backend.delete_object(
1527 1514
            request.user_uniq, v_account, v_container,
b/snf-pithos-app/pithos/api/util.py
1061 1061
    return quotas.popitem()[-1] # assume only one resource
1062 1062

  
1063 1063

  
1064
def api_method(http_method=None, token_required=True, user_required=True, logger=None,
1065
               format_allowed=False, serializations=None,
1066
               strict_serlization=False):
1064
def api_method(http_method=None, token_required=True, user_required=True,
1065
               logger=None, format_allowed=False, serializations=None,
1066
               strict_serlization=False, lock_container_path=False):
1067 1067
    serializations = serializations or ['json', 'xml']
1068 1068
    def decorator(func):
1069 1069
        @api.api_method(http_method=http_method, token_required=token_required,
......
1083 1083
            try:
1084 1084
                # Add a PithosBackend as attribute of the request object
1085 1085
                request.backend = get_backend()
1086
                request.backend.lock_container_path = lock_container_path
1086 1087
                # Many API method expect thet X-Auth-Token in request,token
1087 1088
                request.token = request.x_auth_token
1088 1089
                update_request_headers(request)
b/snf-pithos-backend/pithos/backends/modular.py
1193 1193
        self._can_read(user, account, container, name)
1194 1194
        return (account, container, name)
1195 1195

  
1196
    @backend_method
1197
    def lock_path(self, path):
1198
        node = self.node.node_lookup(path, for_update=True)
1199

  
1200 1196
    @backend_method(autocommit=0)
1201 1197
    def get_block(self, hash):
1202 1198
        """Return a block's data."""
......
1253 1249
        return account, node
1254 1250

  
1255 1251
    def _lookup_container(self, account, container):
1252
        for_update = True if self.lock_container_path else False
1256 1253
        path = '/'.join((account, container))
1257
        node = self.node.node_lookup(path)
1254
        node = self.node.node_lookup(path, for_update)
1258 1255
        if node is None:
1259 1256
            raise ItemNotExists('Container does not exist')
1260 1257
        return path, node

Also available in: Unified diff