parent
0b77810a40
commit
011afb4818
@ -0,0 +1,137 @@ |
||||
# FLocal |
||||
|
||||
## Motivation |
||||
|
||||
This is a fully functional alternative to UBB.threads, |
||||
complete with capability of migration from UBB.threads. |
||||
|
||||
First working release implemented in summer 2010, |
||||
with occasional additional features added from time to time over the next two years. |
||||
|
||||
## Features |
||||
|
||||
It is highly performant, compared to UBB.threads: |
||||
on a mid-range rental server in 2010 (dual-core Nehalem CPU, 8GB RAM, 32-bit PostgreSQL, 7200 RPM HDD) |
||||
with over 10 million posts in the database, |
||||
it handles 1000 simple requests per second with ease, with response time under `DateTime`'s 16ms precision. |
||||
|
||||
In addition to most features of stock UBB.threads, it also supports |
||||
advanced features that were implemented by fbgz.xyz into their custom UBB.threads codebase: |
||||
|
||||
* Layers (normal, offtopic, garbage), with every post having a layer, |
||||
with moderators being able to limit max layer for every user's posts by moderating actions, |
||||
and visibility of layers configurable by every user on per-board basis; |
||||
* Moderation "strikes" (one notice in a specific board is worth one point; one warning, three points; |
||||
notices and warnings have expiration dates; total weight of over 9 or 27 points limits max layer |
||||
for posts of that user in that board); |
||||
* Threads can be locked (so that nobody except administrators can post in them); |
||||
* Default UI of fbgz.xyz (heavily patched over UBB.threads default); |
||||
* "Light" UI for extremely low-traffic surfing (minimal HTML, almost no JS, |
||||
no automatic display of uploaded files); |
||||
* Non-standard colors for usernames of some users (by request); |
||||
* Themes and smileys from fbgz.xyz; |
||||
* New users registration is only allowed from configurable allowlist of specific subnets; |
||||
* etc |
||||
|
||||
and some additional features never implemented by fbgz.xyz: |
||||
|
||||
* Ability to list public uploaded files in order (only for logged-in users); |
||||
* Ability for users to retroactively limit the visibility of all their posts to logged-in users or to nobody at all; |
||||
* Hotlinking for uploaded images is blocked; they can only be viewed when embedded in local posts; |
||||
* "Modern" UI in Metro-style (resembling Zune UI); |
||||
* RSS (as yet another UI variant); |
||||
* Raw XML (as yet another UI variant), for programmatic access by custom user-created applications, |
||||
kind of like an API; |
||||
* Private messages are grouped in threads by user; |
||||
* Instead of "Zone" board (where thread author is a thread moderator), there are "Zone" subboards per user; |
||||
* LaTeX support in posts; |
||||
* Typographic improvements (e.g. double minus is replaced by mdash); |
||||
* Threads are never "archived" (because, as opposed to fbgz.xyz, there are no performance reasons to do so), |
||||
even unpinned threads with last posts over two months old can still be replied to |
||||
(but old posts feature a slowpoke icon for actions, so that it's clear that they're old); |
||||
* Last read post in thread is always tracked |
||||
(as opposed to UBB.threads always marking any thread not visited for over seven days as fully read); |
||||
* A page listing all posts replying to or mentioning any specific user |
||||
(as opposed to listing only posts replying to that user); |
||||
* A page listing all threads by a specific user; |
||||
* Machichara similar to the ones featured on japanese cell phones; |
||||
* Coexistence of imported posts with the new posts; |
||||
regular importing of new posts from UBB.threads instance without conflicts |
||||
with the posts originally created on the new software |
||||
(imported posts always get lower IDs regardless of their date, so they're always displayed below); |
||||
* Multi-language support (at the moment, only Russian and English are supported); |
||||
* etc. |
||||
|
||||
## Technical details |
||||
|
||||
This is mostly a C# 3.5 application, running in IIS 7.5 as a managed IIS module. |
||||
Only one instance is running at a time, which allows to do aggressive caching of DB entries |
||||
(especially considering that there is no 64-bit PostgreSQL on Windows, so PostgreSQL is limited to 2GB RAM). |
||||
|
||||
It is currently running on Windows Server 2008 R2 Web Edition x64 with PostgreSQL 8.4, |
||||
on a Hetzner box with 8GB RAM and 320GB 7200RPM HDD. |
||||
|
||||
This is written completely from scratch; |
||||
the only third-party libraries used are .NET Framework 3.5, |
||||
[Npgsql](https://github.com/npgsql/npgsql) to connect to PostgreSQL, |
||||
[NConsoler](https://github.com/csharpus/nconsoler) for convenient CLI UI of importing tool, |
||||
lightly modified[BBCode parser by PJonDevelopment](http://pjondevelopment.50webs.com/articles/bbcodeParser.html) |
||||
as a base library for BBCode (I implemented support for specific tags), |
||||
and .NET Framework stock XSLT processing library. |
||||
|
||||
This project is 25k LOC of C# code, and 15k LOC of XSLT files (for all supported designs). |
||||
|
||||
## Technical solutions |
||||
|
||||
Key highlights: |
||||
|
||||
### UI |
||||
|
||||
Implemented via pluggable XSLT template sets in [`Resources/FLocal/templates`](Resources/FLocal/templates). |
||||
|
||||
At the moment, only four template sets are implemented: |
||||
|
||||
* Classic: the default one from fbgz.xyz, supporting all its themes; |
||||
* Lite: inspired by the lite UI from fbgz.xyz, but even more efficient traffic-wise; |
||||
* Modern: created from scratch, inspired by look of Metro UIs (such as the one in Zune), with tiles and stuff; |
||||
* RSS: created from scratch, allows subscribing to basically any page |
||||
(board, thread, posts of a specific user, mentions of a specific user, you name it); |
||||
* Not technically a template set: raw XML, unprocessed by XSLT, for programmatic usage by third-party clients |
||||
(e.g. can be used to implement a smartphone app). |
||||
|
||||
### DB |
||||
|
||||
I implemented my own ORM here, with the following features: |
||||
|
||||
* (SQL) DB-agnostic, all postgres-specific quirks are implemented |
||||
in a separate [`PostgresDBTraits.cs`](MySQLConnector/PostgresDBTraits.cs); |
||||
* Agressive caching of all entries fetched from DB; |
||||
since only one instance of the application is supposed to be running at a time, and only on one server, |
||||
we can assume that the data in DB is never changed unless application changed it, |
||||
so we can safely cache everything, and only invalidate specific entries when we ourselves update them. |
||||
This also means that for every entry in db fetched to the application, only one unique object exists in RAM. |
||||
|
||||
Implementation is in [`Registry.cs`](Web.Core/Registry.cs); |
||||
example of usage is in [`Post.cs`](FLocal.Common/dataobjects/Post.cs). |
||||
* Bundling of all DB changes into one complex changeset |
||||
(supporting incrementing values or referring to the newly inserted rows), |
||||
executed in one go without any additional business logic slowing it down, |
||||
ensuring quick transactions and reducing the possibility of conflicts. |
||||
Implementation is in [`ChangeSet.cs`](ChangeSet.cs); |
||||
example of usage is in [`Thread.cs:getNewPostChanges`](FLocal.Common/dataobjects/Thread.cs) for a new reply. |
||||
|
||||
Additionally, changeset executor reorders changes to conform to the ideal table locking order, |
||||
and if that's not possible, locks the required tables early, ensuring that there will be no deadlocks. |
||||
|
||||
### DB patching |
||||
|
||||
There is a separate service intended to keep DB schema up-to-date and to install the latest patches only once, |
||||
and to revert them if needed: [`Updater.cs`](Patcher/Updater.cs). |
||||
|
||||
Example of usage: [`Patch_00002_mentions.xml`](FLocal.Patcher.Common/Resources/Patch_00002_mentions.xml). |
||||
|
||||
### Installation |
||||
|
||||
All builds are packaged as MSI installer files; |
||||
it is enough to run a new MSI file on the server to update to a new version |
||||
that will automatically handle all new requests. |
Loading…
Reference in new issue