Capsule sẽ được gửi định kỳ bởi cache đến active node và sau đó sẽ được trả về cho cache. Việc kết hợp cache với active node được thực hiện bằng cách kiểm tra sự trả về của các Bind capsule. Nếu nhiều capsule liên tiếp không được nhận thì cache có thể xem như active node đã bị hư. Việc kết hợp active node với cache được thực hiện bằng cách đặt địa chỉ của cache trong soft-store với thời gian expire nhắn. Nếu cache hư, thì trạng thái này sẽ được xóa bởi node và code dịch vụ khi 1 capsule đến sẽ được xem như caching hiện nay không tồn tại và sẽ được chuyển qua cho active node tiếp theo. Để đảm bảo rằng cache và acitve node có thể duy trì trạng thái phù hợp khi cái kia bị hư hay restart, thì cache sẽ truyền một epoch ID (đượx định nghĩa là thời gian restart gần nhất) cùng với Bind capsule. Khi các cache đang up và đang chay thì chúng sẽ được sử dụng để phục vụ các yêu cầu web bởi các Query capsule. Những capsule này được gửi bởi client để mở một kết nối để nhận tài liệu yêu cầu, nghĩa là chúng thêm việc xử lý một gói tin TCP-SYN. Đường đi của một Query capsule như sau:
Hình 7. 7 Query capsule processing
Sau đây là mã giả của Query capsule:
public int last; // previous cache
public int found; // cache with hit
public long objectID; // requested object
public boolean evaluate(Node n) {
if (found != 0) { // divert to a found cache
if (n.getAddress() == found) {
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, found);
}
}
// otherwise, are we at a cache -- is there a binding?
Object[] record = (Object[])n.getCache().get("CACHE");
if (record != null) {
// if a cache, is there a redirect record?
Object[] redirect = (Object[])n.getCache().get(objectID);
if (redirect != null) {
// if a redirect too, does it match the binding?
Long bindEpoch = (Long)record[0];
Long redirectEpoch = (Long)redirect[0];
if (bindEpoch.longValue() == redirectEpoch.longValue()) {
found = ((Integer)record[1]).intValue();
if (n.getAddress() == found) {
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, found);}
} else {
n.getCache().remove(objectID); // clear out old data}
}
last = n.getAddress(); // note cache was here
}
if (n.getAddress() == getDst()) { // now continue to server
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, getDst());}
}
Mặc định nó sẽ hướng đến server và dọc đường đi, nó sẽ kiểm tra các acitve node với các cache tương ứng với active node đó, như những thông tin được lưu trong soft-store của active node. Việc kiểm tra này có thể có 3 kết quả: Nếu node không có cache tương ứng với nó thì query sẽ tiếp tục đến server. Nếu có cache kết hợp với active node nhưng nội dung yêu cầu không có trong bảng nội dung của active node thì query vẫn tiếp tục đến server, và ghi chú địa chỉ của active node để node này có thể có cache cho những lần sau. Cuối cùng, nếu có một cache thõa mãn trong bảng nội dung của active node thì query sẽ được chuyển hướng đến cache. Sau đó, sẽ là một quá trình kiểm tra xem active node và cache có thuộc cùng một epoch hay không. Nếu không thì dữ liệu thu được xem như đã cũ và sẽ bị xóa đi. Để ý rằng quá trình này sẽ flush bảng nội dung của active node dần dần khi cache được restart. Trong tất cả trường hợp, query capsule sẽ ít khi rời khỏi mạng khi nó đến được cache phù hợp. Cache hay server nhận được query phải tải downstream cache. Những nhiệm vụ này được thực hiện như là một chuỗi của việc truyền cache. Mỗi làn truyền được thực hiện bằng cách tăng tín hiệu của việc truyền dữ liệu (một kế nối TCP) với các capsule redirect và Activate. Mã giả của 2 capsule này như sau:
Redirect capsule:
public long objectID; // requested object
public int redirect; // redirecting node
public int requestor; // original client
public boolean evaluate(Node n) {
// have we reached the redirecting node?
if ((redirect == 0) && (n.getAddress() == getDst())) {
Object[] record = (Object[])n.getCache().get("CACHE");
redirect = n.getAddress(); // if so, lock
if (record != null) {
setDst(((Integer)record[1]).intValue()); // and head to external cache
} else {
setDst(getSrc()); // failure, return to server?}
}
// continue to redirect, external cache, or server
if (n.getAddress() != getDst()) {
return n.routeForNode(this, getDst());
} else {
return n.deliverToApp(this, dpt);}
}
Hình 7. 8 Redirect & Activate capsule processing
Activate capsule:
public long objectID; // requested object
public long epoch; // cache generation
public int redirect; // cache to redirect
public int activate; // cache we activated
public boolean evaluate(Node n) {
// have we reached the node to activate?
if ((activate == 0) && (n.getAddress() == getDst())) {
Object[] record = (Object[])n.getCache().get("CACHE");
activate = n.getAddress(); // if so, lock
setDst(redirect);
if (record != null) {
long bound = ((Long)record[0]).longValue();
if (bound == epoch) {
Object[] redirect = new Object[2]; // put it in the cache
redirect[0] = (Long)record[0];
n.getCache().put(objectID, redirect, 100);
} else {
return true; // unexpected change, die quietly}
}
}
// continue to node or upstream cache/server
if (n.getAddress() != getDst()) {
return n.routeForNode(this, getDst());
} else {
return n.deliverToApp(this, dpt);}
}
Hình 7. 9 Path of capsule that return a document to the client
Redirect capsule được sử dụng để thiết lập một kết nối giữa các cache, hay giữa cache cuối cùng với client để truyền dữ liệu. Ứng với việc truyền giữa các cache, thì nó được thiết kế để kiêm vai trò của gói tin TCP-SYN giúp thiết lập một kết nối. Với việc truyền cache-to-cache cuối cùng, nó được thiết kế để kiêm vai trò của gói tin TCP-SYN-ACK, giúp chấp nhận một kết nối được khởi tạo bới hành động của Query capsule tương ứng trong vai trò của một TCP-SYN. Không giống với các gói tin bình thường, nó được định tuyến qua các active node tương ứng, được lưu lại trong Query. Điều này cho phép những node đó theo dõi cache hit và bảo đảm rằng các cặp cache sẽ vẫn còn tồn tại. Việc truyền dữ liệu sau đó sẽ diễn ra bình thường, trực tiếp giữa bên nhận và bên gửi mà không có bất kỳ sự xử lý đặc biệt nào cả. Tương tự, Activate capsule được sử dụng để ngắt những kết nối này sau khi chúng đã được sử dụng để truyền dữ liệu. Nó được thiết kế để kiêm vai trò của gói tin TCP-FIN. Giống như Redirect capsule, nó được định tuyến qua các active node tương ứng để cho phép chúng theo dõi tải của cache và cập nhật bảng nội dung của chúng.
Hình 7. 7 Query capsule processing
Sau đây là mã giả của Query capsule:
public int last; // previous cache
public int found; // cache with hit
public long objectID; // requested object
public boolean evaluate(Node n) {
if (found != 0) { // divert to a found cache
if (n.getAddress() == found) {
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, found);
}
}
// otherwise, are we at a cache -- is there a binding?
Object[] record = (Object[])n.getCache().get("CACHE");
if (record != null) {
// if a cache, is there a redirect record?
Object[] redirect = (Object[])n.getCache().get(objectID);
if (redirect != null) {
// if a redirect too, does it match the binding?
Long bindEpoch = (Long)record[0];
Long redirectEpoch = (Long)redirect[0];
if (bindEpoch.longValue() == redirectEpoch.longValue()) {
found = ((Integer)record[1]).intValue();
if (n.getAddress() == found) {
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, found);}
} else {
n.getCache().remove(objectID); // clear out old data}
}
last = n.getAddress(); // note cache was here
}
if (n.getAddress() == getDst()) { // now continue to server
return n.deliverToApp(this, dpt);
} else {
return n.routeForNode(this, getDst());}
}
Mặc định nó sẽ hướng đến server và dọc đường đi, nó sẽ kiểm tra các acitve node với các cache tương ứng với active node đó, như những thông tin được lưu trong soft-store của active node. Việc kiểm tra này có thể có 3 kết quả: Nếu node không có cache tương ứng với nó thì query sẽ tiếp tục đến server. Nếu có cache kết hợp với active node nhưng nội dung yêu cầu không có trong bảng nội dung của active node thì query vẫn tiếp tục đến server, và ghi chú địa chỉ của active node để node này có thể có cache cho những lần sau. Cuối cùng, nếu có một cache thõa mãn trong bảng nội dung của active node thì query sẽ được chuyển hướng đến cache. Sau đó, sẽ là một quá trình kiểm tra xem active node và cache có thuộc cùng một epoch hay không. Nếu không thì dữ liệu thu được xem như đã cũ và sẽ bị xóa đi. Để ý rằng quá trình này sẽ flush bảng nội dung của active node dần dần khi cache được restart. Trong tất cả trường hợp, query capsule sẽ ít khi rời khỏi mạng khi nó đến được cache phù hợp. Cache hay server nhận được query phải tải downstream cache. Những nhiệm vụ này được thực hiện như là một chuỗi của việc truyền cache. Mỗi làn truyền được thực hiện bằng cách tăng tín hiệu của việc truyền dữ liệu (một kế nối TCP) với các capsule redirect và Activate. Mã giả của 2 capsule này như sau:
Redirect capsule:
public long objectID; // requested object
public int redirect; // redirecting node
public int requestor; // original client
public boolean evaluate(Node n) {
// have we reached the redirecting node?
if ((redirect == 0) && (n.getAddress() == getDst())) {
Object[] record = (Object[])n.getCache().get("CACHE");
redirect = n.getAddress(); // if so, lock
if (record != null) {
setDst(((Integer)record[1]).intValue()); // and head to external cache
} else {
setDst(getSrc()); // failure, return to server?}
}
// continue to redirect, external cache, or server
if (n.getAddress() != getDst()) {
return n.routeForNode(this, getDst());
} else {
return n.deliverToApp(this, dpt);}
}
Hình 7. 8 Redirect & Activate capsule processing
Activate capsule:
public long objectID; // requested object
public long epoch; // cache generation
public int redirect; // cache to redirect
public int activate; // cache we activated
public boolean evaluate(Node n) {
// have we reached the node to activate?
if ((activate == 0) && (n.getAddress() == getDst())) {
Object[] record = (Object[])n.getCache().get("CACHE");
activate = n.getAddress(); // if so, lock
setDst(redirect);
if (record != null) {
long bound = ((Long)record[0]).longValue();
if (bound == epoch) {
Object[] redirect = new Object[2]; // put it in the cache
redirect[0] = (Long)record[0];
n.getCache().put(objectID, redirect, 100);
} else {
return true; // unexpected change, die quietly}
}
}
// continue to node or upstream cache/server
if (n.getAddress() != getDst()) {
return n.routeForNode(this, getDst());
} else {
return n.deliverToApp(this, dpt);}
}
Hình 7. 9 Path of capsule that return a document to the client
Redirect capsule được sử dụng để thiết lập một kết nối giữa các cache, hay giữa cache cuối cùng với client để truyền dữ liệu. Ứng với việc truyền giữa các cache, thì nó được thiết kế để kiêm vai trò của gói tin TCP-SYN giúp thiết lập một kết nối. Với việc truyền cache-to-cache cuối cùng, nó được thiết kế để kiêm vai trò của gói tin TCP-SYN-ACK, giúp chấp nhận một kết nối được khởi tạo bới hành động của Query capsule tương ứng trong vai trò của một TCP-SYN. Không giống với các gói tin bình thường, nó được định tuyến qua các active node tương ứng, được lưu lại trong Query. Điều này cho phép những node đó theo dõi cache hit và bảo đảm rằng các cặp cache sẽ vẫn còn tồn tại. Việc truyền dữ liệu sau đó sẽ diễn ra bình thường, trực tiếp giữa bên nhận và bên gửi mà không có bất kỳ sự xử lý đặc biệt nào cả. Tương tự, Activate capsule được sử dụng để ngắt những kết nối này sau khi chúng đã được sử dụng để truyền dữ liệu. Nó được thiết kế để kiêm vai trò của gói tin TCP-FIN. Giống như Redirect capsule, nó được định tuyến qua các active node tương ứng để cho phép chúng theo dõi tải của cache và cập nhật bảng nội dung của chúng.