N/A A.P.D. Deason
Internet-Draft Sine Nomine
Intended status: Informational April 12, 2011
Expires: October 14, 2011

Base Types for Time in AFS-3
draft-deason-afs3-type-time-01

Abstract

This document defines two types to be used in future AFS-3 Rx Remote Procedure Calls (RPCs) to represent time. Current AFS-3 RPCs represent time as 32-bit integers representing seconds. This is insufficient in both granularity and range, so new types to represent time are defined in this document to overcome these limitations.

Internet Draft Comments

Comments regarding this draft are solicited. Please include the AFS-3 protocol standardization mailing list (afs3-standardization@openafs.org) as a recipient of any comments.

Status of this Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet- Drafts is at http://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on October 14, 2011.

Copyright Notice

Copyright (c) 2011 IETF Trust and the persons identified as the document authors. All rights reserved.

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) in effect on the date of publication of this document. Please review these documents carefully, as they describe your rights and restrictions with respect to this document.


Table of Contents

1. Introduction

All extant AFS-3 RPCs represent time as a 32-bit integer, as encoded by XDR in [RFC4506], which represents a number of seconds. For RPCs that specify an absolute time, this is the number of seconds that have passed since since midnight or 0 hour January 1, 1970 Coordinated Universal Time (UTC), not counting leap seconds. These time structures will be unusable after January 2038, and are already insufficient to represent time with more granularity than one second.

This limited granularity creates inefficiencies in various parts of the AFS-3 protocol when it must be determined in what order two events have occurred (for example, whether or not a file was changed since the last time a volume has been backed up). When those two events have occurred during the same second, implementations must take a conservative assumption about which event occurred first, often resulting in unnecessary duplication or retransmission of data. In addition, metadata can be lost when files are copied to AFS from other filesystems that store file modification times with finer granularity than one second.

This document defines three new types to represent time to overcome these limitations: AFSTimestamp, AFSRelTimestamp, and AFSTime. All of these support a much wider time range at a much higher granularity than the current time representations. AFSRelTimestamp is to be used to represent times relative to some other event, and AFSTimestamp is to be used to represent absolute time stamps. AFSTime is to be used to represent a small range of absolute time, which is necessary for determining relative ordering of events, as described in Section 4.

All of these new types also have the additional benefit of providing standard type identifiers to be used when specifying absolute or relative time in AFS-3 RPC arguments and structures. Currently, all time values are just defined as "afs_int32" types in the XDR language definitions. This can make it confusing whether or not a field is an absolute time, relative time, or something else completely. Using the new standard time types will make this clear and unambiguous.

2. Conventions Used in this Document

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC2119].

3. Data Types

This document defines three new data types: AFSTimestamp, AFSRelTimestamp, and AFSTime. All of these are encoded on the wire using the XDR standard described in [RFC4506], and are described using the XDR language specification therein.

3.1. AFSTimestamp

The new AFSTimestamp type is represented as an XDR-encoded 64-bit unsigned integer representing the timestamp. It is defined as thus in XDR:

    typedef unsigned hyper AFSTimestamp;

The AFSTimestamp type represents the amount of time that has passed since midnight or 0 hour January 1, 1601 Coordinated Universal Time (UTC). The value represents this amount of time in increments of 100 nanoseconds (ns). This precision and starting date is equivalent to the Microsoft Windows FILETIME structure.

For example, to represent the time 60 seconds after midnight on January 1, 1601, the value of the field would be 600000000 (600 million).

This structure can represent any time from January 1, 1601 up to the year 30282 with 100-ns granularity.

3.2. AFSRelTimestamp

The new AFSRelTimestamp type has nearly the same representation on the wire as AFSTimestamp in Section 3.1:

    typedef hyper AFSRelTimestamp;

The AFSRelTime type represents the amount of time that has passed since some other event. The event to which this time is relative is unspecified, and can be anything; it must be specified by the RPC or structure that defines a field of the AFSRelTime type.

The value represents this amount of time in increments of 100 ns. Values greater than 0 represent dates that occur after the relative event, and values less than 0 represent dates that occur before the relative event.

For example, to represent the time 5 seconds before some other event, the value of the timestamp field would be -50000000 (negative 50 million).

3.3. AFSTime

The new AFSTime type is represented as an XDR-encoded structure on the wire, containing an AFSTimestamp and a 32-bit unsigned integer representing the resolution. It is defined as thus in XDR:

    struct AFSTime {
        AFSTimestamp timestamp;
        unsigned int resolution;
    };

The AFSTime structure represents the amount of time that has passed since midnight or 0 hour January 1, 1601 Coordinated Universal Time (UTC). The value of the timestamp field is this amount of time represented as described in Section 3.1.

The resolution field represents the resolution of the time source from which the timestamp was obtained. The value of the resolution field is the difference between the represented time, and another time after the represented time that is guaranteed to be after the actual time at which the event in question occurred.

In other words, let X be the time that some event occurred, Y be the value of the timestamp field in an AFSTime structure, and Z be the value of the resolution field. To construct an AFSTime structure that represents X, the values of the timestamp and resolution field MUST be specified such that Y <= X < Y + Z. Typically the value of the resolution field will just be the resolution of the time source from which the timestamp was obtained, if the resolution of the time source is constant.

For example, to represent the time 60 seconds after midnight on January 1, 1601, the value of the timestamp field would be 600000000 (600 million) as described in Section 3.1. If this time stamp was obtained from a source that only represents time in seconds, the next representable time is 61 seconds after midnight on January 1, 1601, so it is guaranteed that the event in question occurred before that time (otherwise the time source would give us a time of 61 seconds). So the value of the resolution field should be 10000000 (10 million). In effect, this AFSTime structure represents an event that occurred at or after 60 seconds after January 1, 1601, but occurred before 61 seconds after January 1, 1601.

For more details about the resolution field (including the motivation for its existence), see Section 4.

3.3.1. Resolution Assumptions

If the resolution field has the value of 0, the resolution of the specified timestamp is unknown. If an implementation has absolutely no mechanism to determine the resolution of a time source when creating a time stamp, it MUST specify a resolution of 0. If an implementation needs to use an AFSTime value for calculating event ordering, and the resolution is 0, it SHOULD assume a resolution of 1 second, and round the timestamp down to the nearest second.

An AFS-3 implementation MUST NOT ever specify a resolution greater than 1 second (10000000 100-ns increments). Implementations of the AFS-3 protocol that exist prior to the introduction of the new time types in this document assume that the time resolution is 1 second, and may not behave correctly with time sources that are less granular than 1 second. No systems nor file formats that are related to any AFS-3 implementation are known that do not have at least 1-second granularity, so adhering to this should not be a problem.

If an implementation receives an AFSTime structure with a granularity coarser than 1 second, it MUST treat it as an invalid time representation. What that entails depends on the context, but the AFSTime value MUST NOT be used for any calculations and SHOULD be immediately discarded. Typically an RPC will raise some kind of error in this condition, but the exact behavior is up to the relevant RPC or other operation.

4. Time Resolution

The new type AFSTime includes information about the resolution or granularity of the time it represents. The reason for including this information may not be immediately clear, so this section provides some information on why this information is beneficial.

4.1. Sources of Differing Time Resolutions

All current AFS-3 implementations represent time as a 32-bit integer on the wire, and so it is common for implementations to internally represent time as 32-bit integers, with 1-second granularity. As such, when implementations support the time types defined in this document, it is likely that there will be a period of time where implementations cannot store or represent time with greater granularity than 1-second, even though the protocol allows them to do so.

In addition, due to technical restrictions of various platforms, or other sources of time (such as file formats), implementations may be only able to transmit time information in certain granularities. For example, the operating system that an AFS-3 Volume Server implementation runs on may only be able to retrieve the current time in increments of 1 millisecond. Or, an AFS-3 Volume Server implementation may be reading the time information from a file, and the file only represents time in increments of 1 second.

From this, it is clear that implementations will send time of various granularity when communicating with other services and clients in AFS-3, and the granularity of time may vary even within the same implementation process (depending on from where it is obtaining the time).

4.2. Relevance to AFS-3

Timestamps are sometimes used in AFS-3 to establish a relative non-strict total ordering of events. That is, given the events X and Y, we must determine whether X or Y occurred first, or if they occurred at approximately the same time. This primarily occurs in volume operations when incremental data is sent, and exactly what incremental data is sent is determined by the timestamps of other volumes. If we get the ordering wrong, problems with data inconsistency can occur. If we conservatively determine that two events occurred at the same time when we could have correctly made the determination that one occurred before the other, inefficiencies arise.

In order to be able to order such events, then, we must know the resolution of the time value that is stored. This is so we know the earliest possible time that the event occurred, and the latest possible time that the event occurred.

4.3. When to Include Resolution Information

There are two time types defined in this document to represent an absolute timestamp: AFSTimestamp and AFSTime. The only difference between these two types is that AFSTime includes resolution information, and AFSTimestamp does not. This section serves to guide designers of future AFS-3 RPCs in what circumstances each type should be used.

When deciding whether to use AFSTimestamp or AFSTime in a structure field or RPC argument, the first determination that must be made is whether the timestamp value will or could ever be used to make ordering decisions by an AFS-3 service. If it will or could, then the argument or field should be of the AFSTime type.

Otherwise, the determination should be made whether or not any service (possibly unrelated to AFS-3) may realistically make ordering decisions based on the field or argument. If it may, then the AFSTime type should be considered; otherwise, the AFSTimestamp type should be used.

For example, as mentioned in Section 4.2, the AFS-3 Volume Service and clients make ordering decisions based on timestamps related to when volume operations have occurred. So, timestamp fields related to volume operations should probably use the AFSTime type.

However, when a timestamp is used to represent the modification time of a file in AFS, that timestamp is not used by AFS-3 services to make any ordering decisions. While it is possible that some software unrelated to AFS-3 may try to make ordering decisions based off of that timestamp, it is unlikely to be able to do so reliably. This is because file modification timestamps can usually be set to any time by humans, and any time resolution information stored is usually not available to programs that are not AFS-3-aware. And in general, AFS-3 file metadata is not intended to be a general-purpose distributed synchronization mechanism. So, file modification timestamps should probably use the AFSTimestamp type.

5. Converting Time Types

In general, when converting an AFSTimestamp or AFSTime value to some other type that has granularity coarser than 100 ns granularity, the resulting value MUST always be rounded down to the nearest lower increment of the resultant type. When converting to the POSIX time_t type, for example, the AFSTimestamp or AFSTime value MUST be rounded down to the nearest lower second. When converting to the POSIX struct timeval type, the value MUST be rounded down to the nearest lower microsecond.

POSIX time values are also typically specified in terms of the amount of time that has passed since midnight 1 January 1970 UTC. Since AFSTime and AFSTimestamp times are specified relative to midnight 1 January 1601 UTC, an offset must be added or subtracted when converting. When converting from an AFSTimestamp to a POSIX time_t, the value 116444736000000000 should be subtracted from the AFSTimestamp before converting to seconds. Similarly, when converting to an AFSTimestamp value from a POSIX time_t, the value 116444736000000000 should be added after converting to 100 ns increments.

When converting to or from a Microsoft FILETIME structure, the values can be simply copied, as the granularity and starting date are the same.

It is also important to keep in mind that when converting from AFSTime to time_t or FILETIME types, strictly speaking the AFSTime structure represents two times: the beginning and end time. So it is impossible to accurately convert an AFSTime structure to a single time value. This is often unavoidable when converting to legacy AFS-3 interfaces, or interfaces unrelated to AFS-3, however, and when only one time value is given to convert to, implementations MUST specify the beginning time (that is, the time represented by the timestamp field).

5.1. Special Cases

Extant AFS-3 RPCs often use a timestamp of 0 to represent a special meaning. That is, a timestamp of 0 often does not indicate midnight 1 January 1970 UTC, but may represent a logical value of "negative infinity", or indicates some special meaning that is specific to that RPC. The value of 0 was often just used because it is the earliest representable time for a 32-bit unsigned integer.

Any such special meanings must be specified by the RPC in question, and this document assigns no special meaning to the value of 0 for any of the types defined in this document. However, this document recommends that any future RPCs keep the special meaning of the 0 timestamp, if the RPC is replacing an RPC that previously had a special meaning for timestamp 0. If the new RPC uses an AFSTime argument, the resolution field should be 0, as well.

For example, say there is an AFS-3 RPC called AFSFoo that accepts an afs_uint32 absolute timestamp argument, and it specifies that a timestamp of 0 represents some special case. Let another RPC, AFSFoo64, define an RPC that is identical to AFSFoo except that it accepts an AFSTime parameter. AFSFoo64 should specify that a caller should specify an AFSTime with timestamp 0, resolution 0, to indicate the special case previously indicated by giving a 32-bit timestamp of 0, even though those represent two different times.

5.2. Sample Code

Sample C code is provided here to convert AFSTimestamp, AFSRelTimestamp, and AFSTime values to and from FILETIME and POSIX time_t values where appropriate. Also provided is a function to compare two AFSTime values, and functions to add an AFSRelTimestamp to an AFSTime and AFSTimestamp.

The conversion functions assume that the special cases described in Section 5.1 are relevant. So, a time_t with the value of 0 will be converted to an AFSTimestamp with the value of 0, or an AFSTime value of timestamp 0, resolution 0, instead of converting to the value that represents midnight 1 Jan 1970. AFSTime structures with a resolution of 0 (and a non-zero timestamp) are treated as having an effective resolution of 1 second, as suggested in Section 3.3.1.

These functions do not handle overflow, underflow, or other errors, and are just guidelines for the general conversion algorithms.

#define AFSTIME_POSIX_SHIFT 116444736000000000ULL
#define AFSTIME_POSIX_SCALE 10000000U
#define AFSTIME_DEFAULT_RES 10000000U

void
timet_to_AFSTimestamp(time_t t, AFSTimestamp *atsp)
{
    if (t == 0) {
        *atsp = 0;
    } else {
        *atsp = (t * AFSTIME_POSIX_SCALE) + AFSTIME_POSIX_SHIFT;
    }
}
void
AFSTimestamp_to_timet(AFSTimestamp ats, time_t *tp)
{
    if (ats == 0) {
        *tp = 0;
    } else {
        *tp = ((ats - AFSTIME_POSIX_SHIFT) / AFSTIME_POSIX_SCALE);
    }
}
void
timet_to_AFSRelTimestamp(time_t t, AFSRelTimestamp *artsp)
{
    *artsp = (t * AFSTIME_POSIX_SCALE);
}
void
AFSRelTimestamp_to_timet(AFSRelTimestamp arts, time_t *tp)
{
    *tp = (arts / AFSTIME_POSIX_SCALE);
}
void
timet_to_AFSTime(time_t t, AFSTime *atp)
{
    timet_to_AFSTimestamp(t, &atp->timestamp);
    if (t == 0) {
        atp->resolution = 0;
    } else {
        atp->resolution = AFSTIME_POSIX_SCALE;
    }
}
void
AFSTime_to_timet(AFSTime *atp, time_t *t1, time_t *t2)
{
    unsigned int res = atp->resolution;
    if (res == 0) {
        res = AFSTIME_DEFAULT_RES;
    }
    AFSTimestamp_to_timet(atp->timestamp, t1);
    AFSTimestamp_to_timet(atp->timestamp + res, t2);
}
void
FILETIME_to_AFSTimestamp(FILETIME *ftp, AFSTimestamp *atsp)
{
    ULARGE_INTEGER uli;
    uli.LowPart = ftp->dwLowDateTime;
    uli.HighPart = ftp->dwHighDateTime;
    *atsp = uli.QuadPart;
}
void
AFSTimestamp_to_FILETIME(AFSTimestamp ats, FILETIME *ftp)
{
    ULARGE_INTEGER uli;
    uli.QuadPart = ats;
    ftp->dwLowDateTime = uli.LowPart;
    ftp->dwHighDateTime = uli.HighPart;
}
void
AFSTime_to_FILETIME(AFSTime *atp, FILETIME *ft1, FILETIME *ft2)
{
    unsigned int res = atp->resolution;
    if (res == 0) {
        res = AFSTIME_DEFAULT_RES;
    }
    AFSTimestamp_to_FILEMTIME(atp->timestamp, ft1);
    AFSTimestamp_to_FILEMTIME(atp->timestamp + res, ft2);
}
void
AFSTime_add_AFSRelTimestamp(AFSTime *atp, AFSRelTimestamp arts)
{
    atp->timestamp += arts;
}
void
AFSTimestamp_add_AFSRelTimestamp(AFSTimestamp *atsp,
                                 AFSRelTimestamp arts)
{
    *atsp += arts;
}
int
cmp_AFSTime(AFSTime *atp1, AFSTime *atp2)
{
    unsigned int res1 = atp1->resolution;
    unsigned int res2 = atp2->resolution;
    if (res1 == 0) {
        res1 = AFSTIME_DEFAULT_RES;
    }
    if (res2 == 0) {
        res2 = AFSTIME_DEFAULT_RES;
    }
    if (atp1->timestamp + res1 <= atp2->timestamp) {
        return -1;
    }
    if (atp2->timestamp + res2 <= atp1->timestamp) {
        return 1;
    }
    return 0;
}

6. Security Considerations

This memo raises no security issues.

7. IANA Considerations

This document makes no request of the IANA.

8. Acknowledgements

The author thanks Simon Wilkinson and Jeffrey Altman for some background text, and Jeffrey Altman, David Boyes, Tom Keiser, and Simon Wilkinson for discussion on the problem of time resolution.

9. References

9.1. Normative References

[RFC2119] Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, March 1997.

9.2. Informative References

[RFC4506] Eisler, M., "XDR: External Data Representation Standard", STD 67, RFC 4506, May 2006.

Author's Address

Andrew Deason Sine Nomine Associates 43596 Blacksmith Square Ashburn, Virginia 20147-4606 USA Phone: +1 703 723 6673 EMail: adeason@sinenomine.net