Add ceil method to utils.Timestamp

There are a few places where a last-modified value is calculated by
rounding a timestamp *up* to the nearest second. This patch refactors
to use a new Timestamp.ceil() method to do this rounding, along with a
clarifying docstring.

Change-Id: I9ef73e5183bdf21b22f5f19b8440ffef6988aec7
This commit is contained in:
Alistair Coles 2022-05-06 15:18:15 +01:00
parent 7298038ed9
commit 52254bb5ca
6 changed files with 27 additions and 13 deletions

View File

@ -1350,6 +1350,18 @@ class Timestamp(object):
isoformat += ".000000"
return isoformat
def ceil(self):
"""
Return the 'normal' part of the timestamp rounded up to the nearest
integer number of seconds.
This value should be used whenever the second-precision Last-Modified
time of a resource is required.
:return: a float value with second precision.
"""
return math.ceil(float(self))
def __eq__(self, other):
if other is None:
return False

View File

@ -17,7 +17,6 @@ import json
import os
import time
import traceback
import math
from eventlet import Timeout
@ -598,7 +597,7 @@ class ContainerController(BaseStorageServer):
is_sys_or_user_meta('container', key)))
headers['Content-Type'] = out_content_type
resp = HTTPNoContent(request=req, headers=headers, charset='utf-8')
resp.last_modified = math.ceil(float(headers['X-PUT-Timestamp']))
resp.last_modified = Timestamp(headers['X-PUT-Timestamp']).ceil()
return resp
def update_data_record(self, record):
@ -804,7 +803,7 @@ class ContainerController(BaseStorageServer):
ret = Response(request=req, headers=resp_headers, body=body,
content_type=out_content_type, charset='utf-8')
ret.last_modified = math.ceil(float(resp_headers['X-PUT-Timestamp']))
ret.last_modified = Timestamp(resp_headers['X-PUT-Timestamp']).ceil()
if not ret.body:
ret.status_int = HTTP_NO_CONTENT
return ret

View File

@ -24,7 +24,6 @@ import multiprocessing
import time
import traceback
import socket
import math
from eventlet import sleep, wsgi, Timeout, tpool
from eventlet.greenthread import spawn
@ -1113,7 +1112,7 @@ class ObjectController(BaseStorageServer):
key.lower() in self.allowed_headers):
response.headers[key] = value
response.etag = metadata['ETag']
response.last_modified = math.ceil(float(file_x_ts))
response.last_modified = file_x_ts.ceil()
response.content_length = obj_size
try:
response.content_encoding = metadata[
@ -1181,7 +1180,7 @@ class ObjectController(BaseStorageServer):
response.headers[key] = value
response.etag = metadata['ETag']
ts = Timestamp(metadata['X-Timestamp'])
response.last_modified = math.ceil(float(ts))
response.last_modified = ts.ceil()
# Needed for container sync feature
response.headers['X-Timestamp'] = ts.normal
response.headers['X-Backend-Timestamp'] = ts.internal

View File

@ -14,7 +14,6 @@
# limitations under the License.
import json
import math
import random
import six
@ -170,8 +169,8 @@ class ContainerController(Controller):
# GETorHEAD_base does not, so don't set it here either
resp = Response(request=req, body=shard_range_body)
update_headers(resp, headers)
resp.last_modified = math.ceil(
float(headers['x-put-timestamp']))
resp.last_modified = Timestamp(
headers['x-put-timestamp']).ceil()
resp.environ['swift_x_timestamp'] = headers.get(
'x-timestamp')
resp.accept_ranges = 'bytes'

View File

@ -1009,8 +1009,7 @@ class ReplicatedObjectController(BaseObjectController):
etag = etags.pop() if len(etags) else None
resp = self.best_response(req, statuses, reasons, bodies,
'Object PUT', etag=etag)
resp.last_modified = math.ceil(
float(Timestamp(req.headers['X-Timestamp'])))
resp.last_modified = Timestamp(req.headers['X-Timestamp']).ceil()
return resp
@ -3498,6 +3497,5 @@ class ECObjectController(BaseObjectController):
resp = self.best_response(req, statuses, reasons, bodies,
'Object PUT', etag=etag,
quorum_size=min_conns)
resp.last_modified = math.ceil(
float(Timestamp(req.headers['X-Timestamp'])))
resp.last_modified = Timestamp(req.headers['X-Timestamp']).ceil()
return resp

View File

@ -305,6 +305,13 @@ class TestTimestamp(unittest.TestCase):
for value in test_values:
self.assertEqual(utils.Timestamp(value).isoformat, expected)
def test_ceil(self):
self.assertEqual(0.0, utils.Timestamp(0).ceil())
self.assertEqual(1.0, utils.Timestamp(0.00001).ceil())
self.assertEqual(1.0, utils.Timestamp(0.000001).ceil())
self.assertEqual(12345678.0, utils.Timestamp(12345678.0).ceil())
self.assertEqual(12345679.0, utils.Timestamp(12345678.000001).ceil())
def test_not_equal(self):
ts = '1402436408.91203_0000000000000001'
test_values = (