Sunday, September 28, 2008

Java NIO [reading note]




- NIO is primarily block oriented, java.io uses streams
page-oriented nature of system I/O (disk, file)
stream I/O, OS provides non-blocking, readiness selection support

- Channels are conduits to OS I/O service, not stream. They do bulk data transfer to and from buffer, channel.write(buffer) ~= buffer.get(byteArray), channel.read(buffer)~= buffer.put(byteArray). Data is logically transferred in blocks, not char/byte at a time.

- Channels are gateways through which the native I/O services of the operating system can be accessed with a minimum of overhead, and buffers are the internal endpoints used by channels to send and receive data. Channel implementations often use native code. The channel interfaces allow you to gain access to low-level I/O services in a controlled and portable way.

- The new socket channels can operate in nonblocking mode and are selectable. These two capabilities enable multiplexed I/O.

- Readiness selection effectively prevents you from separating the code that checks for readiness from the code that processes the data, at least without significant complexity.

- A SelectionKey encapsulates the registration relationship between a specific channel and a specific selector. SelectionKey objects contain two bit sets (encoded as integers) interest set and ready set indicating which channel operations the registrant has an interest in and which operations the channel is ready to perform.

- Building Highly Scalable Servers with Java NIO has a good discussion on thread model:

  • M dispatchers/no workers
Several event-dispatch threads doing all the work (dispatching events, reading, processing requests, and writing).
  • 1 dispatcher/N workers
A single event-dispatch thread and multiple worker threads.
  • M dispatchers/N workers
Multiple event dispatch threads and multiple worker threads.

- More thread != More efficient. More thread means more context switching overhead. Actual concurrency is limited by the number of CPUs available.

See: Introducing Nonblocking Sockets

Monday, September 22, 2008

Form.target

Use Case: Sometimes you may want a form to be processed and the result displayed in a different window (popup->main, main->popup).

target is a read/write string property of the Form object. It specifies the name of the frame or window in which the results of the submission of form should be displayed. Four special target names are supported: _blank, _parent, _self and _top.


<script>
function openwin() {
  window.open("about:blank", "winDocPrint", "..size,etc");
}
</script>


<form action="printdoc.php?sa=<?php echo session_id(); ?>" target="winDocPrint" onsubmit="openwin">
...
</form>

** sa=<?php echo session_id(); ?> is URL rewriting used to keep the same session in the new window. And session_start() must be invoked on new window to resume the current one based on the current session id that's being passed via a request.

Friday, September 12, 2008

Non-blocking Socket

The problem

Importance of Java as a language and runtime platform for server application grows with every day. A fundamental trait of a server application is that it services multiple clients concurrently. The only way to achieve concurrency before JDK 1.4 was to allocate a separate thread of execution for servicing every connection. While this model is quite easy to implement, it contains inherent scalability problems. First, a server that maps one connection to one thread can not serve more concurrent connections than it can allocate threads. Second, while threads - from the developer's standpoint - provide a convenient virtualization of available CPU resources, they are costly both in terms of space (each thread requires a separate call stack) and time (context switching a CPU between threads consumes time). All these factors impose limits on both the number of connections the server can process at any given time, as well as on the effective throughput. Last, but not least the threads will potentially spend a significant part of their processing time blocked in I/O operations. This makes the server vulnerable to a particular kind of denial-of-service attacks, where a malicious client can bog down the server by opening many connections to it (therefore allocating all available threads), and then send it a completely valid request extremely slowly (say, one byte per minute). This effect can be caused even with otherwise benevolent clients sitting behind narrow bandwidth connections.

The solution

If you are concerned with any of these problems (support for extremely large number of connections, throughput maximization, and protection from service degradation due to slow clients), you should write your servers in a non-blocking fashion. This means a radical paradigm shift - instead of allocating a dedicated thread to serve a connection, a single thread (or eventually several threads) service a large number of connections using an event-driven mechanism. In the event-driven architecture, one thread watches multiple network sockets, and when one or more sockets are ready to be read from or written to, the thread recieves an event and gets the chance to service those connections that became ready. However, this architecture assumes the availability of a non-blocking I/O library, since a crucial requirement is that the thread must never block on an I/O operation.

Also, the way network protocol is implemented in a non-blocking world is drastically different than in the blocking world. With the blocking, one-thread-per connection paradigm, you encapsulate a network protocol in a procedural way, that is you write a code that is executed on a thread that is dedicated to executing the code for its single connection. You can store much of the processing state on the stack: local variables, call arguments, and the code execution path itself. On the contrary, in the non-blocking world, your code is invoked to process one or two packets of data at a time and then it returns control. Therefore, you can't contain any state on the stack, as you would Essentially, you must write a finite-state machine where events (incoming packet and empty outgoing network buffer) drive state transitions.

Thursday, September 11, 2008

Message Bus



A message bus specializes in transporting messages between applications. A message bus contains three key elements:

    * A set of agreed-upon message schemas
    * A set of common command messages [Hohpe04]
    * A shared infrastructure for sending bus messages to recipients

When you use a message bus, an application that sends a message no longer has individual connections to all the applications that must receive the message. Instead, the application merely passes the message to the message bus, and the message bus transports the message to all the other applications that are listening for bus messages through a shared infrastructure. Likewise, an application that receives a message no longer obtains it directly from the sender. Instead, it takes the message from the message bus. In effect, the message bus reduces the fan-out of each application from many to one.

Usually, the bus does not preserve message ordering. Internal optimizations, routing, buffering, or even the underlying transport mechanism might affect how the messages travel to the receiving applications. Therefore, the order in which messages reach each receiver is nondeterministic.

See: Prescriptive Architecture Message Bus

Wednesday, September 10, 2008

Concurrent Programming in Java [reading note]

- Overriding run() in Thread vs. Using Runnable as an argument in Thread constructor
   Default strategy is to define Runnable as a separate class and supply it in a Thread constructor. Isolating code within a distinct class relieves you of worrying about any potential interactions of synchronized methods or blocks used in the Runnable with any that may be used by methods of class Thread.
   A small proof for Composition over Inheritance.

- Method Adapter patterns
   Besides adapter, sub-classing, template method, the most flexible approach to before/after control is to define a class whose entire purpose is to invoke a particular method on a particular object. In the command object pattern and its many variants, instances of such classes can then be passed around, manipulated, and ultimately executed. In some other languages, function pointers and closures are defined and used to achieve some of these effects.


interface Callable {
   Object call(Object arg) throws Exception;
}

- Collection Traveral
   Lock the whole collection and operate on each item may be time consuming. JDK's Iterator is a fast-fail iterator that throw a ConcurrentModificationException if the collection is modified in the midst of a traversal using the version approach.