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