Jump to content
Matt
 Share


IP.Board 3: Topic Marking Overhaul

Topic markers have evolved quite a bit over the past few years. What started out as being an almost secondary concern has become quite an important part of the user experience.

A Very Brief History
Early versions of IP.Board relied on cookies to track read topics. This worked fairly well but it wasn't without problems. Anything to do with cookies is always a little flaky. There is a very finite amount of information you can store and browsers have a habit of eating them or not setting them correctly. The biggest complaint, however, is that topics that you have read on one computer do not stay read on another computer.

IP.Board 2 introduced topic markers that are stored in a database table. This greatly increased stability and allowed the read topics to remain read regardless of computer used.

However, this did lead to some performance issues on busier boards as the topic marker table is often in demand whcih can result in locking issues and processes queueing. Also, the code wasn't centralized and sprawled through different files making maintenance very difficult.

Learning From Experience

It was obvious we needed to centralize all the code and create a common, simple public interface as a matter of course. We also wanted to allow our other applications (such as blog and gallery) to use this system without having to copy code. Making it truly extensible also allows modification authors to use this centralized system without having to maintain their own code.

Next up was the performance issue. How could we increase performance without losing functionality? The most obvious answer was to store the read topics in the user's session. This was fine in principle but there were obstacles to overcome. First of all, session handling in IP.Board 2 is not entirely centralized. There is a class but it is not used exclusively. Other files such as register.php and login.php are allowed to modify the session table without telling other classes what it did. When you're trying to preserve data, this cannot be allowed. Also, session handling in general isn't an exact science. IP addresses change meaning new sessions can be created several times during a single visit.

The solution to these problems must be robust, centralized and extensible.

So, what's new?
First up was tightening up session handling. All session management is now performed through a single class (publicSessions). Other files that need to manage sessions are done so via publicSessions. This allows this one class to keep tight control over the session data.

The biggest challenge was to allow sessions to handle the marker data and only allowing the markers to be written back to the database table when the session is deleted. The theory is sound and simple but the execution a little trickier. The gory details of which are explained a littler further down for the technically minded.

In brief, the system loads the markers from the database table when a new member session is created. The markers are saved in with the rest of the session data when the session is updated at the end of a page view (to update the running time and location, etc). This continues until the session is due to be removed, for example, when the member is no longer active and the session is older than the allowed time. The sessions to be removed are captured and allowed to be examined by other classes. The item marking class examines these sessions and writes back the marker information to the marker database. The system also makes use of cookies to give some permanence for guests and those that are not logged in. The cookies are limited to the last 100 items read to prevent cookies being sent that are too large.

The end result is a much leaner system which should be much more efficient and presents a very simple public interface. Here's some sample code to give you a taste:

$itemMarking->markRead( array( 'forumID' => 2, 'topicID' => 10 ) ); # To fetch the read status of an item if ( $itemMarking->isRead( array( 'forumID' => 2, 'itemID' => 99, 'itemLastUpdate' => 1200098989 ) ) === TRUE ) {     .... } # To fetch the last time an item was marked $lastMarked = $itemmarking->fetchTimeLastMarked( array( 'forumID' => 2, 'itemID' => 99 ) );

 # To mark an item read (an item is a topic for the forums 'application')











Modification authors can write their own plug-ins and make use of the system with minimal coding effort.

Listen Up, Here Comes The Science Bit
For the more technically minded, this section explains how the system works within the new IP.Board 3.0.0 framework.

The first challenge was to make proper use of __construct and __destruct within PHP 5. This is very straightforward in the case of __construct; this is run when the class is initialized. There are no problems with that. The item marking class grabs and filters the cookie data and also grabs and filters the session item marking data in __construct.

The real issue is with __destruct. Specifically the order in which they are called. In PHP 5.0.0 to PHP 5.2.4 they are called in the order they were created. This means that by the time __destruct() is called in item Marking the DB connection has been closed which isn't at all helpful. This is because the DB is set up before classItemMarking. Now, as of PHP 5.2.5 the __destruct order has been reversed. This means that the DB connection will still be available.
However, that's not very convenient for code that has to be robust on different platforms and with unpredictable version of PHP. Another solution was needed.

Thankfully register_shutdown_function() executes before any __destruct() calls, so we can reliably use this. There is a __myDestruct function in the ipsRegistry class which calls __myDestruct() in all the registry child classes (DB, Member, Request, Cache, Settings, etc). The member registry class makes use of this to fire a manual destruct function within itemMarking to allow it to save back any data for deleted sessions and to provide information for the session update. A __myDestruct fires within the public session class to actually update the sessions and delete the expired ones.

Phew! As you can see, there's a lot going on behind the scenes in IP.Board 3.0.0 which makes full use of all PHP 5 has to offer.

 Share

Comments

Recommended Comments


That is a good thing for the upgrade of my Ticket System :o

But now we want a preview and not only words!! :P

It was obvious we needed to centralize all the code and create a common, simple public interface as a matter of course. We also wanted to allow our other applications (such as blog and gallery) to use this system without having to copy code. Making it truly extensible also allows modification authors to use this centralized system without having to maintain their own code.

Link to comment
Share on other sites

So if I understand this correctly... It would do this in PHP 5.2.4 or earlier:

DB : Construct
Marker : Construct
DB : Destruct
Marker : Destruct

And it PHP 5.2.5 and later, it would do this (correctly):

DB : Construct
Marker : Construct
Marker : Destruct
DB : Destruct

...

What was Zend smoking when they first implemented destruct? I'm glad I read this.. I'm not quite into PHP 5 yet, and this will be a great help knowing this for the future.. So how exactly did you implement the shut down function?

Link to comment
Share on other sites

Matt, I think you got the version numbers wrong. 5.2.5 was released in november 07. And according to the change logs, this issue was fixed in 5.2.0.

http://bugs.php.net/bug.php?id=36759

I would certainly hope that this isn't an issue from 5.2.1. to 5.2.4.. Because if it is, that means it's only been fixed for 10 months. If it was indeed fixed in 5.2.0, it would mean it's been fixed for 1 year and 10 months, which would make me feel a whole lot better :).

Link to comment
Share on other sites

IPB is hitting the ball out of the park this time around! I am happy I didn't jump ship to VBulletin as I had been seriously contemplating over the last year! Thanks for listening to the customers and caring about what we wanted in IPB this time around!

Link to comment
Share on other sites

  • Management

Luke - I may have got my numbers confused, I did a lot of research and read a lot of different things on the subject.

The general consensus was to not trust the destruct order within PHP. Even the function notes say this so I felt it wise to avoid the problem altogether with register_shutdown.

Link to comment
Share on other sites

  • Management

[quote name='bobage24' date='Sep 11 2008, 07:13 PM']IPB is hitting the ball out of the park this time around! I am happy I didn't jump ship to VBulletin as I had been seriously contemplating over the last year! Thanks for listening to the customers and caring about what we wanted in IPB this time around!

We've always listened. :) IP.Board 3 is a great chance to "right some wrongs". We've always avoided large changes for smaller releases but this time we get to wipe the slate completely clean.

Link to comment
Share on other sites



Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...