Commit Graph

507 Commits

Author SHA1 Message Date
Sam Young
1c09bf86a4 Add @SafeVarargs to PromiseAggregator#add and PromiseNotifier#(...) https://github.com/netty/netty/issues/3147
Motivation:

8fbc513 introduced stray warnings in callsites of
PromiseAggregator#add and PromiseNotifier#(...).

Modifications:

This commit adds the @SafeVarargs annotation to PromiseAggregator#add
and PromiseNotifier#(...). As Netty is built with JDK7, this is a
recognized annotation and should not affect runtime VM versions 1.5 and
1.6.

Result:

Building Netty with JDK7 will no longer produce warnings in the
callsites mentioned above.
2014-12-01 19:59:52 +01:00
Trustin Lee
37e1788a7c Fix awful naming 2014-11-22 07:46:40 +09:00
Trustin Lee
759a2b9abe Add back IntObjectMap.values(Class<V>)
Motivation:

Although the new IntObjectMap.values() that returns Collection is
useful, the removed values(Class<V>) that returns an array is also
useful. It's also good for backward compatibility.

Modifications:

- Add IntObjectMap.values(Class<V>) back
- Miscellaneous improvements
  - Cache the collection returned by IntObjectHashMap.values()
  - Inspector warnings
- Update the IntObjectHashMapTest to test both values()

Result:

- Backward compatibility
- Potential performance improvement of values()
2014-11-22 07:42:33 +09:00
Trustin Lee
f8a13cc3e9 Backport the IntObjectHashMap changes in f23f3b9617
Motivation:

The mentioned commit contains a bug fix and an improvement in
IntObjectHashMap that requires backporting.

Modifications:

Update IntObjectMap, IntObjectHashMap, and IntObjectHashMapTest

Result:

Easier to backport HTTP/2 and other changes in master in the future
2014-11-21 11:09:51 +09:00
Idel Pivnitskiy
3d200085a4 Small performance improvements
Motivation:

Found performance issues via FindBugs and PMD.

Modifications:

- Removed unnecessary boxing/unboxing operations in DefaultTextHeaders.convertToInt(CharSequence) and DefaultTextHeaders.convertToLong(CharSequence). A boxed primitive is created from a string, just to extract the unboxed primitive value.
- Added a static modifier for DefaultHttp2Connection.ParentChangedEvent class. This class is an inner class, but does not use its embedded reference to the object which created it. This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary.
- Added a static compiled Pattern to avoid compile it each time it is used when we need to replace some part of authority.
- Improved using of StringBuilders.

Result:

Performance improvements.
2014-11-20 00:58:35 -05:00
Trustin Lee
59f222a821 Handle the interface name in IPv6 address correctly
Motivation:

NetUtil.isValidIpV6Address() handles the interface name in IPv6 address
incorrectly. For example, it returns false for the following addresses:

- ::1%lo
- ::1%_%_in_name_

Modifications:

- Strip the square brackets before validation for simplicity
- Strip the part after the percent sign completely before validation for
  simplicity
- Simplify and reformat NetUtilTest

Result:

- The interface names in IPv6 addresses are handled correctly.
- NetUtilTest is cleaner
2014-11-12 12:15:14 +09:00
Sam Young
bb94f05083 Add generic versions of PromiseAggregator and PromiseNotifier.
Motivation:

ChannelPromiseAggregator and ChannelPromiseNotifiers only allow
consumers to work with Channels as the result type. Generic versions
of these classes allow consumers to aggregate or broadcast the results
of an asynchronous execution with other result types.

Modifications:

Add PromiseAggregator and PromiseNotifier. Add unit tests for both.
Remove code in ChannelPromiseAggregator and ChannelPromiseNotifier and
modify them to extend the new base classes.

Result:

Consumers can now aggregate or broadcast the results of an asynchronous
execution with results types other than Channel.
2014-11-07 08:44:20 +01:00
Trustin Lee
49998bc9c0 Fix build errors introduced during backporting SslContext 2014-10-31 14:25:14 +09:00
Scott Mitchell
56b8bb30b2 Backport ALPN and Mutual Auth SSL
Motivation:

Improvements were made on the main line to support ALPN and mutual
authentication for TLS. These should be backported.

Modifications:

- Backport commits from the master branch
  - f8af84d599
  - e74c8edba3

Result:

Support for ALPN and mutual authentication.
2014-10-31 14:15:12 +09:00
Norman Maurer
1914b77c71 [maven-release-plugin] prepare for next development iteration 2014-10-29 11:48:40 +01:00
Norman Maurer
c170e7df3f [maven-release-plugin] prepare release netty-4.0.24.Final 2014-10-29 11:47:19 +01:00
Frederic Bregier
2fc421b2ba Backport 4.1 to 4.0 on HttpPostRequestDecoder
Motivation
4.0 was not modified in the same time than 4.1 while the difference was
limited.
Include the fix on "=" character in Boundary.

Issue #3004 shows that "=" character was not supported as it should in
the HttpPostRequestDecoder in form-data boundary.

Modifications:
Backport from 4.1 to 4.0 while respecting interfaces.

Add 2 methods in StringUtil
- split with maxParm argument: String split with max parts only (to prevent multiple '='
to be source of extra split while not needed)
- substringAfter: String part after delimiter (since first part is not
needed)
Use those methods in HttpPostRequestDecoder.
Change and the HttpPostRequestDecoderTest to check using a boundary
beginning with "=".

Results:
Backport done (Issue #2886 fix)
Issue #3004 fix too
The fix implies more stability and fix the relative issues.
2014-10-21 16:05:08 +09:00
nmittler
76de0a7567 Slight performance improvement to IntObjectHashMap.hashIndex()
Motivation:

Using a needless local copy of keys.length.

Modifications:

Using keys.length explicitly everywhere.

Result:

Slight performance improvement of hashIndex.
2014-10-20 12:39:25 -07:00
nmittler
c6053b8698 Optimize IntObjectHashMap handling of negative keys.
Motivation:

The hashIndex method currently uses a conditional to handle negative
keys. This could be done without a conditional to slightly improve
performance.

Modifications:

Modified hashIndex() to avoid using a conditional.

Result:

Slight performance improvement to hashIndex().
2014-10-20 10:59:27 -07:00
nmittler
c1217b9dd3 Allowing negative keys in IntObjectHashMap.
Motivation:

IntObjectHashMap throws an exception when using negative values for
keys.

Modifications:

Changed hashIndex() to normalize the index if the mod operation returns
a negative number.

Result:

IntObjectHashMap supports negative key values.
2014-10-20 18:08:26 +02:00
Trustin Lee
31862cca18 Fix a bug in NetUtil.createByteArrayFromIpAddressString()
Motivation:

An IPv6 string can have a zone index which is followed by the '%' sign.
When a user passes an IPv6 string with a zone index,
NetUtil.createByteArrayFromIpAddressString() returns an incorrect value.

Modification:

- Strip the zone index before conversion

Result:

An IPv6 string with a zone index is decoded correctly.
2014-10-14 17:50:31 +09:00
Amir Szekely
fe785c2308 Don't ignore maxCapacity if it's not a power of 2
Motivation:

This fixes bug #2848 which caused Recycler to become unbounded and cache infinite number of objects with maxCapacity that's not a power of two. This can result in general sluggishness of the application and OutOfMemoryError.

Modifications:

The test for maxCapacity has been moved out of test to check if the buffer has filled. The buffer is now also capped at maxCapacity and cannot grow over it as it jumps from one power of two to the other.

Additionally, a unit test was added to verify maxCapacity is honored even when it's not a power of two.

Result:

With these changes the user is able to use a custom maxCapacity number and not have it ignored. The unit test assures this bug will not repeat itself.
2014-08-31 09:11:01 +02:00
Norman Maurer
ed50eb8781 Avoid redundant reads of head in peakNode
Motivation:

There is not need todo redunant reads of head in peakNode as we can just spin on next() until it becomes visible.

Modifications:

Remove redundant reads of head in peakNode. This is based on @nitsanw's patch for akka.
See https://github.com/akka/akka/pull/15596

Result:

Less volatile access.
2014-08-21 08:44:17 +02:00
Norman Maurer
67d0b6fe4d Code-inspection fixes
Motivation:

Saw some code-inspection warnings

Modifications:

Fix warnings

Result:

Less code-inspection warnings
2014-08-21 07:32:42 +02:00
Norman Maurer
2c5ab129e5 Document the correct default value of SOMAXCONN
Motivation:

Recently we changed the default value of SOMAXCONN that is used when we can not determine it by reading /proc/sys/net/core/somaxconn. While doing this we missed to update the javadocs to reflect the new default value that is used.

Modifications:

List correct default value in the javadocs of SOMAXCONN.

Result:

Correct javadocs.
2014-08-18 06:05:38 +02:00
Trustin Lee
7710e7da44 [maven-release-plugin] prepare for next development iteration 2014-08-16 03:02:02 +09:00
Trustin Lee
208198c0cb [maven-release-plugin] prepare release netty-4.0.23.Final 2014-08-16 03:01:57 +09:00
Trustin Lee
d3729b6335 Reduce the fallback SOMAXCONN value
Related issue: #2407

Motivation:

The current fallback SOMAXCONN value is 3072.  It is way too large
comparing to the default SOMAXCONN value of popular OSes.

Modifications:

Decrease the fallback SOMAXCONN value to 128 or 200 depending on the
current OS

Result:

Saner fallback value
2014-08-14 15:42:22 -07:00
Trustin Lee
a2d508711d [maven-release-plugin] prepare for next development iteration 2014-08-14 09:41:33 +09:00
Trustin Lee
3051db9d59 [maven-release-plugin] prepare release netty-4.0.22.Final 2014-08-14 09:41:28 +09:00
Norman Maurer
1e5501d304 [#2744] Fix flakey HashedWheelTimerTest.testExecutionOnTime()
Motivation:

The calculation of the max wait time for HashedWheelTimerTest.testExecutionOnTime() was wrong and so the test sometimes failed.

Modifications:

Fix the max wait time.

Result:

No more test-failures
2014-08-06 07:03:58 +02:00
Trustin Lee
b3c5d67bbd Fix a bug where ChannelFuture.setFailure(null) doesn't fail
Motivation:

We forgot to do a null check on the cause parameter of
ChannelFuture.setFailure(cause)

Modifications:

Add a null check

Result:

Fixed issue: #2728
2014-08-05 11:23:28 -07:00
Trustin Lee
fb5583d788 Refactoring in preparation to unify I/O logic for all branches
Motivation:

While trying to merge our ChannelOutboundBuffer changes we've made last
week, I realized that we have quite a bit of conflicting changes at 4.1
and master. It was primarily because we added
ChannelOutboundBuffer.beforeAdd() and moved some logic there, such as
direct buffer conversion.

However, this is not possible with the changes we've made for 4.0. We
made ChannelOutboundBuffer final for example.

Maintaining multiple branch is already getting painful and having
different core will make it even worse, so I think we should keep the
differences between 4.0 and other branches minimal.

Modifications:

- Move ChannelOutboundBuffer.safeRelease() to ReferenceCountUtil
- Add ByteBufUtil.threadLocalBuffer()
  - Backported from ThreadLocalPooledDirectByteBuf
- Make most methods in AbstractUnsafe final
  - Add AbstractChannel.filterOutboundMessage() so that a transport can
    convert a message to another (e.g. heap -> off-heap), and also
    reject unsupported messages
  - Move all direct buffer conversions to filterOutboundMessage()
  - Move all type checks to filterOutboundMessage()
- Move AbstractChannel.checkEOF() to OioByteStreamChannel, because it's
  the only place it is used at all
- Remove ChannelOutboundBuffer.current(Object), because it's not used
  anymore
- Add protected direct buffer conversion methods to AbstractNioChannel
  and AbstractEpollChannel so that they can be used by their subtypes
- Update all transport implementations according to the changes above

Result:

- The missing extension point in 4.0 has been added.
  - AbstractChannel.filterOutboundMessage()
  - Thanks to the new extension point, we moved all transport-specific
    logic from ChannelOutboundBuffer to each transport implementation
- We can copy most of the transport implementations in 4.0 to 4.1 and
  master now, so that we have much less merge conflict when we modify
  the core.
2014-08-05 08:04:23 +02:00
Trustin Lee
021ecd45c3 More brief somaxconn logging
- Consistent log message format
- Avoid unnecessary autoboxing when debug level is off
- Remove the duplication of somaxconn path
2014-08-04 10:25:11 -07:00
Norman Maurer
d9934e5fb4 Remove duplicated code 2014-07-31 18:10:11 -07:00
Norman Maurer
d10983b7f4 [#2720] Check if /proc/sys/net/core/somaxconn exists before try to parse it
Motivation:

As /proc/sys/net/core/somaxconn does not exists on non-linux platforms you see a noisy stacktrace when debug level is enabled while the static method of NetUtil is executed.

Modifications:

Check if the file exists before try to parse it.

Result:

Less noisy logging on non-linux platforms.
2014-07-31 18:05:18 -07:00
Trustin Lee
91639b3dbf Use our own URL shortener wherever possible 2014-07-31 17:05:54 -07:00
Norman Maurer
e282e504f1 Optimize gathering write in the epoll transport
Motivation:

While benchmarking the native transport, I noticed that gathering write
is not as fast as expected.  It was due to the fact that we have to do a
lot of array copies to put the buffer addresses into the iovec struct
array.

Modifications:

Introduce a new class called IovArray, which allows to fill buffers
directly into an off-heap array of iovec structs, so that it can be
passed over to JNI without any extra array copies.

Result:

Big performance improvement when doing gathering writes:

Before:

[nmaurer@xxx]~% wrk/wrk -H 'Host: localhost' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Connection: keep-alive' -d 120 -c 256 -t 16 --pipeline 256  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
  16 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    23.44ms   16.37ms 259.57ms   91.77%
    Req/Sec   181.99k    31.69k  304.60k    78.12%
  346544071 requests in 2.00m, 46.48GB read
Requests/sec: 2887885.09
Transfer/sec:    396.59MB

After:

[nmaurer@xxx]~% wrk/wrk -H 'Host: localhost' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Connection: keep-alive' -d 120 -c 256 -t 16 --pipeline 256  http://xxx:8080/plaintext
Running 2m test @ http://xxx:8080/plaintext
  16 threads and 256 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    21.93ms   16.33ms 305.73ms   92.34%
    Req/Sec   194.56k    33.75k  309.33k    77.04%
  369617503 requests in 2.00m, 49.57GB read
Requests/sec: 3080169.65
Transfer/sec:    423.00MB
2014-07-30 14:57:13 -07:00
Norman Maurer
d989b24351 [#2662] Fix race in cancellation of TimerTasks which could let to NPE
Motivation:

Due some race-condition while handling canellation of TimerTasks it was possibleto corrupt the linked-list structure that is represent by HashedWheelBucket and so produce a NPE.

Modification:

Fix the problem by adding another MpscLinkedQueue which holds the cancellation tasks and process them on each tick. This allows to use no synchronization / locking at all while introduce a latency of max 1 tick before the TimerTask can be GC'ed.

Result:

No more NPE
2014-07-25 06:34:49 +02:00
Osvaldo Doederlein
0ae7f2f5e1 Fixes and improvements to IntObjectHashMap. Related to [#2659]
- Rewrite with linear probing, no state array, compaction at cleanup
- Optimize keys() and values() to not use reflection
- Optimize hashCode() and equals() for efficient iteration
- Fixed equals() to not return true for equals(null)
- Optimize iterator to not allocate new Entry at each next()
- Added toString()
- Added some new unit tests
2014-07-21 16:44:19 +02:00
Idel Pivnitskiy
dd026eb60a Fix NPE problems
Motivation:

Now Netty has a few problems with null values.

Modifications:

- Check File in DiskFileUpload.toString().
If File is null we will get NPE when calling toString() method.
- Check Result<String> in MqttDecoder.decodeConnectionPayload(...).
- Check Unsafe before calling unsafe.getClass() in PlatformDependent0 static block.
- Removed unnecessary null check in WebSocket08FrameEncoder.encode(...).
Because msg.content() can not return null.
- Removed unnecessary null checks in ConcurrentHashMapV8.removeTreeNode(TreeNode<K,V>).
- Removed unnecessary null check in OioDatagramChannel.doReadMessages(List<Object>).
Because tmpPacket.getSocketAddress() always returns new SocketAddress instance.
- Removed unnecessary null check in OioServerSocketChannel.doReadMessages(List<Object>).
Because socket.accept() always returns new Socket instance.
- Pass Unpooled.buffer(0) instead of null inside CloseWebSocketFrame(boolean, int) constructor.
If we will pass null we will get NPE in super class constructor.
- Added throw new IllegalStateException in GlobalEventExecutor.awaitInactivity(long, TimeUnit) if it will be called before GlobalEventExecutor.execute(Runnable).
Because now we will get NPE. IllegalStateException will be better in this case.
- Fixed null check in OpenSslServerContext.setTicketKeys(byte[]).
Now we throw new NPE if byte[] is not null.

Result:

Added new null checks when it is necessary, removed unnecessary null checks and fixed some NPE problems.
2014-07-20 12:56:21 +02:00
Idel Pivnitskiy
13569481bf Small fixes and improvements
Motivation:

Fix some typos in Netty.

Modifications:

- Fix potentially dangerous use of non-short-circuit logic in Recycler.transfer(Stack<?>).
- Removed double 'the the' in javadoc of EmbeddedChannel.
- Write to log an exception message if we can not get SOMAXCONN in the NetUtil's static block.
2014-07-20 09:36:57 +02:00
Idel Pivnitskiy
01b11ca2cb Small performance improvements
Modifications:

- Added a static modifier for CompositeByteBuf.Component.
This class is an inner class, but does not use its embedded reference to the object which created it. This reference makes the instances of the class larger, and may keep the reference to the creator object alive longer than necessary.
A boxed primitive is created from a String, just to extract the unboxed primitive value.
- Removed unnecessary checks if file exists before call mkdirs() in NativeLibraryLoader and PlatformDependent.
Because the method mkdirs() has this check inside.

Conflicts:
	codec-http/src/main/java/io/netty/handler/codec/http/multipart/DiskAttribute.java
	codec-stomp/src/main/java/io/netty/handler/codec/stomp/StompSubframeAggregator.java
	codec-stomp/src/main/java/io/netty/handler/codec/stomp/StompSubframeDecoder.java
2014-07-20 09:29:33 +02:00
Norman Maurer
17b9e01780 Fix over-sensible testcase 2014-07-13 17:19:15 +02:00
Norman Maurer
08426d5554 [#2651] Fix possible infinite-loop when cancel tasks
Motivations:
In our new version of HWT we used some kind of lazy cancelation of timeouts by put them back in the queue and let them pick up on the next tick. This  multiple problems:
 - we may corrupt the MpscLinkedQueue if the task is used as tombstone
 - this sometimes lead to an uncessary delay especially when someone did executed some "heavy" logic in the TimeTask

Modifications:
Use a Lock per HashedWheelBucket for save and fast removal.

Modifications:
Cancellation of tasks can be done fast and so stuff can be GC'ed and no more infinite-loop possible
2014-07-11 15:41:22 +02:00
Trustin Lee
0623df12a5 Log the time taken for generating the initialSeedUniquifier
- Sometimes useful to know it how long it takes from the log, to make
  sure it's not something else that is blocking.
2014-07-04 13:27:18 +09:00
Trustin Lee
0a8ff3b52d Fix most inspector warnings
Motivation:

It's good to minimize potentially broken windows.

Modifications:

Fix most inspector warnings from our profile
Update IntObjectHashMap

Result:

Cleaner code
2014-07-02 20:21:30 +09:00
Norman Maurer
016bdfbf66 Correctly return from selector loop one a scheduled task is ready for processing
Motivation:

We use the nanoTime of the scheduledTasks to calculate the milli-seconds to wait for a select operation to select something. Once these elapsed we check if there was something selected or some task is ready for processing. Unfortunally we not take into account scheduled tasks here so the selection loop will continue if only scheduled tasks are ready for processing. This will delay the execution of these tasks.

Modification:

- Check if a scheduled task is ready after selecting
- also make a tiny change in NioEventLoop to not trigger a rebuild if nothing was selected because the timeout was reached a few times in a row.

Result:

Execute scheduled tasks on time.
2014-07-02 08:31:47 +02:00
Norman Maurer
e8f4def2a3 [maven-release-plugin] prepare for next development iteration 2014-06-30 14:31:08 +02:00
Norman Maurer
25e3c8ce3d [maven-release-plugin] prepare release netty-4.0.21.Final 2014-06-30 14:29:15 +02:00
Norman Maurer
522b3e1b92 [#2604] Not try to use sun.misc.Cleaner when on android
Motivation:

When a user tries to use netty on android it currently fails with "Could not find class 'sun.misc.Cleaner'"

Modification:

Encapsulate sun.misc.Cleaner usage in extra class to workaround this isssue.

Result:
Netty can be used on android again
2014-06-27 08:18:21 +02:00
Norman Maurer
b4b61c1f41 [#2599] Not use sun.nio.ch.DirectBuffer as it not exists on android
Motivation:

During some refactoring we changed PlatformDependend0 to use sun.nio.ch.DirectBuffer for release direct buffers. This broke support for android as the class does not exist there and so an exception is thrown.

Modification:

Use again the fieldoffset to get access to Cleaner for release direct buffers.

Result:
Netty can be used on android again
2014-06-25 15:01:57 +02:00
Norman Maurer
790c63e8d2 Improve performance of Recycler
Motivation:

Recycler is used in many places to reduce GC-pressure but is still not as fast as possible because of the internal datastructures used.

Modification:

 - Rewrite Recycler to use a WeakOrderQueue which makes minimal guaranteer about order and visibility for max performance.
 - Recycling of the same object multiple times without acquire it will fail.
 - Introduce a RecyclableMpscLinkedQueueNode which can be used for MpscLinkedQueueNodes that use Recycler

These changes are based on @belliottsmith 's work that was part of #2504.

Result:

Huge increase in performance.

4.0 branch without this commit:

Benchmark                                                (size)   Mode   Samples        Score  Score error    Units
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    00000  thrpt        20 116026994.130  2763381.305    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    00256  thrpt        20 110823170.627  3007221.464    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    01024  thrpt        20 118290272.413  7143962.304    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    04096  thrpt        20 120560396.523  6483323.228    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    16384  thrpt        20 114726607.428  2960013.108    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    65536  thrpt        20 119385917.899  3172913.684    ops/s
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 297.617 sec - in io.netty.microbench.internal.RecyclableArrayListBenchmark

4.0 branch with this commit:

Benchmark                                                (size)   Mode   Samples        Score  Score error    Units
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    00000  thrpt        20 204158855.315  5031432.145    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    00256  thrpt        20 205179685.861  1934137.841    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    01024  thrpt        20 209906801.437  8007811.254    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    04096  thrpt        20 214288320.053  6413126.689    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    16384  thrpt        20 215940902.649  7837706.133    ops/s
i.n.m.i.RecyclableArrayListBenchmark.recycleSameThread    65536  thrpt        20 211141994.206  5017868.542    ops/s
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 297.648 sec - in io.netty.microbench.internal.RecyclableArrayListBenchmark
2014-06-24 08:09:19 +02:00
Trustin Lee
3775a6124e Remove padding utility classes
- It's not used anywhere
2014-06-21 17:59:20 +09:00
Trustin Lee
6834c2da51 Add missing last padding / Comment 2014-06-21 17:57:29 +09:00