src/jdk.jfr/share/classes/jdk/jfr/internal/consumer/ChunkHeader.java
author egahlin
Tue, 15 May 2018 20:24:34 +0200
changeset 50113 caf115bb98ad
child 52850 f527b24990d7
permissions -rw-r--r--
8199712: Flight Recorder Reviewed-by: coleenp, ihse, erikj, dsamersoff, mseledtsov, egahlin, mgronlun Contributed-by: erik.gahlin@oracle.com, markus.gronlund@oracle.com
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
50113
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     1
/*
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     2
 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     3
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     4
 *
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     5
 * This code is free software; you can redistribute it and/or modify it
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     6
 * under the terms of the GNU General Public License version 2 only, as
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     7
 * published by the Free Software Foundation.  Oracle designates this
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     8
 * particular file as subject to the "Classpath" exception as provided
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
     9
 * by Oracle in the LICENSE file that accompanied this code.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    10
 *
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    11
 * This code is distributed in the hope that it will be useful, but WITHOUT
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    14
 * version 2 for more details (a copy is included in the LICENSE file that
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    15
 * accompanied this code).
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    16
 *
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    17
 * You should have received a copy of the GNU General Public License version
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    18
 * 2 along with this work; if not, write to the Free Software Foundation,
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    20
 *
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    22
 * or visit www.oracle.com if you need additional information or have any
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    23
 * questions.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    24
 */
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    25
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    26
package jdk.jfr.internal.consumer;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    27
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    28
import java.io.DataInput;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    29
import java.io.IOException;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    30
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    31
import jdk.jfr.internal.LogLevel;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    32
import jdk.jfr.internal.LogTag;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    33
import jdk.jfr.internal.Logger;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    34
import jdk.jfr.internal.MetadataDescriptor;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    35
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    36
public final class ChunkHeader {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    37
    private static final long METADATA_TYPE_ID = 0;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    38
    private static final byte[] FILE_MAGIC = { 'F', 'L', 'R', '\0' };
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    39
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    40
    private final short major;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    41
    private final short minor;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    42
    private final long chunkSize;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    43
    private final long chunkStartTicks;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    44
    private final long ticksPerSecond;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    45
    private final long chunkStartNanos;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    46
    private final long metadataPosition;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    47
 //   private final long absoluteInitialConstantPoolPosition;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    48
    private final long absoluteChunkEnd;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    49
    private final long absoluteEventStart;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    50
    private final long absoluteChunkStart;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    51
    private final boolean lastChunk;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    52
    private final RecordingInput input;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    53
    private final long durationNanos;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    54
    private final long id;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    55
    private long constantPoolPosition;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    56
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    57
    public ChunkHeader(RecordingInput input) throws IOException {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    58
        this(input, 0, 0);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    59
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    60
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    61
    private ChunkHeader(RecordingInput input, long absoluteChunkStart, long id) throws IOException {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    62
        input.position(absoluteChunkStart);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    63
        if (input.position() >= input.size()) {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    64
            throw new IOException("Chunk contains no data");
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    65
        }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    66
        verifyMagic(input);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    67
        this.input = input;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    68
        this.id = id;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    69
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk " + id);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    70
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startPosition=" + absoluteChunkStart);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    71
        major = input.readRawShort();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    72
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: major=" + major);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    73
        minor = input.readRawShort();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    74
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: minor=" + minor);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    75
        if (major != 1 && major != 2) {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    76
            throw new IOException("File version " + major + "." + minor + ". Only Flight Recorder files of version 1.x and 2.x can be read by this JDK.");
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    77
        }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    78
        chunkSize = input.readRawLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    79
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: chunkSize=" + chunkSize);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    80
        this.constantPoolPosition = input.readRawLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    81
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: constantPoolPosition=" + constantPoolPosition);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    82
        metadataPosition = input.readRawLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    83
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: metadataPosition=" + metadataPosition);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    84
        chunkStartNanos = input.readRawLong(); // nanos since epoch
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    85
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startNanos=" + chunkStartNanos);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    86
        durationNanos = input.readRawLong(); // duration nanos, not used
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    87
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: durationNanos=" + durationNanos);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    88
        chunkStartTicks = input.readRawLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    89
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: startTicks=" + chunkStartTicks);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    90
        ticksPerSecond = input.readRawLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    91
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.INFO, "Chunk: ticksPerSecond=" + ticksPerSecond);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    92
        input.readRawInt(); // features, not used
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    93
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    94
        // set up boundaries
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    95
        this.absoluteChunkStart = absoluteChunkStart;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    96
        absoluteChunkEnd = absoluteChunkStart + chunkSize;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    97
        lastChunk = input.size() == absoluteChunkEnd;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    98
        absoluteEventStart = input.position();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
    99
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   100
        // read metadata
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   101
        input.position(absoluteEventStart);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   102
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   103
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   104
    public ChunkHeader nextHeader() throws IOException {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   105
        return new ChunkHeader(input, absoluteChunkEnd, id + 1);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   106
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   107
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   108
    public MetadataDescriptor readMetadata() throws IOException {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   109
        input.position(absoluteChunkStart + metadataPosition);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   110
        input.readInt(); // size
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   111
        long id = input.readLong(); // event type id
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   112
        if (id != METADATA_TYPE_ID) {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   113
            throw new IOException("Expected metadata event. Type id=" + id + ", should have been " + METADATA_TYPE_ID);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   114
        }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   115
        input.readLong(); // start time
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   116
        input.readLong(); // duration
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   117
        long metadataId = input.readLong();
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   118
        Logger.log(LogTag.JFR_SYSTEM_PARSER, LogLevel.TRACE, "Metadata id=" + metadataId);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   119
        // No need to read if metadataId == lastMetadataId, but we
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   120
        // do it for verification purposes.
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   121
        return MetadataDescriptor.read(input);
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   122
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   123
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   124
    public boolean isLastChunk() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   125
        return lastChunk;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   126
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   127
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   128
    public short getMajor() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   129
        return major;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   130
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   131
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   132
    public short getMinor() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   133
        return minor;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   134
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   135
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   136
    public long getAbsoluteChunkStart() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   137
        return absoluteChunkStart;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   138
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   139
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   140
    public long getConstantPoolPosition() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   141
        return constantPoolPosition;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   142
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   143
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   144
    public long getStartTicks() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   145
        return chunkStartTicks;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   146
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   147
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   148
    public double getTicksPerSecond() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   149
        return ticksPerSecond;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   150
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   151
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   152
    public long getStartNanos() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   153
        return chunkStartNanos;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   154
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   155
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   156
    public long getEnd() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   157
        return absoluteChunkEnd;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   158
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   159
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   160
    public long getSize() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   161
        return chunkSize;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   162
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   163
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   164
    public long getDuration() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   165
        return durationNanos;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   166
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   167
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   168
    public RecordingInput getInput() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   169
        return input;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   170
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   171
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   172
    private static void verifyMagic(DataInput input) throws IOException {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   173
        for (byte c : FILE_MAGIC) {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   174
            if (input.readByte() != c) {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   175
                throw new IOException("Not a Flight Recorder file");
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   176
            }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   177
        }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   178
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   179
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   180
    public long getEventStart() {
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   181
        return absoluteEventStart;
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   182
    }
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   183
caf115bb98ad 8199712: Flight Recorder
egahlin
parents:
diff changeset
   184
}