Gosh, it's getting awfully close to my self imposed deadline of April isn't it - though I think I'll be pulling an Ubuntu and saying "I meant the end of April, honest". Sysadmin stuff got in the way for rather longer than I intended.
Due to making changes all over the place, I currently have a giant change entry on the future branch with all the changes on it. I'll try to factor them out into individual line items later, keeping it reviewable. I'm not going to try to make every intermediate stage work - let alone even compile - because it's too much makework for no benefit. That said, here's where things are! (long, but hopefully interesting to at least some other people... if nothing else a handy memory jogger for me if I get side-tracked at all) Rewritten (greatly simplified) API for getting file names: ========================================================== char *fname = mailbox_meta_fname(&mailbox, META_INDEX); char *newfname = mailbox_meta_newfname(&mailbox, META_INDEX); (uses a separate static buffer so you can just do this and then your rename logic!) char *fname = mailbox_message_fname(&mailbox, uid); So that simplifies HEAPS of code and hides all the "is it meta" behind one interface. Mboxlist functions return a struct ================================== struct mboxlist_entry mbentry; r = mboxlist_lookup(name, &mbentry, &tid); mbentry.mbtype, mbentry.partition, mbentry.acl Simplifies parameter passing to functions considerably Locking ======= Here's the big one! I'll write a separate section on this in more detail, but here are the basic contracts: New file: cyrus.lock - empty file. exclusive lock on cyrus.lock: * free reign with all files. Delete what you like, rewrite what you like * no other locks required shared lock on cyrus.lock: * MUST NOT replace cyrus.index or cyrus.cache files (change inode) * MUST NOT change any files at all without cyrus.index lock * MAY rewrite cyrus.squat. exclusive lock on cyrus.index: * MUST have a shared lock on cyrus.lock * MAY rewrite flags/modseq on any index record * MAY append new index records * MAY append to cyrus.cache * MUST NOT rewrite older parts of cyrus.cache * MAY rewrite cyrus.header (write .NEW, rename) * MAY rewrite user.seen file shared lock on cyrus.index: * optional - gives consistent reads. Otherwise modseqs higher than last read header may be found, seen may be out of sync. I have a simple concurrency test case that can see unintended data by being clever. All this infrastructure is in place in the future branch now, though untested so far. APIs are: mailbox_open_shared(name, auth_state, &mailbox); mailbox_open_exclusive(name, auth_state, &mailbox); mailbox_lock_index(&mailbox); mailbox_unlock_index(&mailbox); mailbox_close(&mailbox); CRCs and automatic bookkeeping ============================== (remember the discussion on recno replacing msgno because expunged records remain in cyrus.index rather than cyrus.expunge, so need to be skipped? It's necessary for the above, because cyr_expire will get an exclusive lock on the mailbox for the duration of its index rewrite!) Move "deleted / flagged / answered" meta count management into mailbox.c: mailbox_rewrite_index_record(&mailbox, recno, &record); * reads the OLD record again, updates counts, updates CRC32 values including XOR_CRC which is the XOR of all record CRCs. * updates "exists" if it's an expunge. * updates modseq value. Calls: mailbox_index_dirty(&mailbox) * anything doing a write to ANYTHING does this. It sets a flag, increments the highestmodseq and grabs a timestamp. All changes use these values. mailbox_header_write(&mailbox); * rewrites the header file. Also updates the mailbox->header_file_crc value which will be saved when we call: mailbox_write_index_header(&mailbox); * MUST be called after making any change to ensure all checksums and XOR_CRC are correctlly stored - along with the bumped highestmodseq and correct record counts. Oh, we missed: mailbox_append_index_records(&mailbox, &records, num); Stores "num" records to the index file. It's a pointer to an array of "struct index_record" structs. I'm still reworking everything to use these rather than doing the bookkeeping by hand! index.c - use a mailbox object ============================== All the globals go away! There's just a global mailbox struct, which will have a lock_fd in shared mode, meaning that all the offsets into the cyrus.index and cyrus.cache mmaps are ALWAYS VALID. Along with compulsary CONDSTORE - vast swathes of code complexity are being removed :) You don't need to track times when you have modseq to determine if flags should be sent again. You don't have to keep statting files, just re-read the header and then scan for updates. It WILL be necessary to keep a global array mapping from msgno to recno so non-UID commands can be efficient. This can be rewritten whenever highestmodseq is detected to have changed :) I'm just starting on this - hence there are lots of global references to remove. Also - no more UID(msgno) and CACHE_OFFSET(msgno) and all that jazz. We read a record with mailbox_read_index_record() and then use it. In native form, in an easily accessible struct. Joy. No more htonl((bit32 *)base_offset+SOME_CONSTANT) nonsense everywhere! Contain it, wrap it, ensure accesses to it go via consistency checking, checksum updating and header counter maintaining paths! So - that's the status of the future branch! It also has most of the interesting patches from the fastmail branch cherry-picked forwards to sit on top of CVS trunk. Feel free to poke around, make suggestions, send patches, etc. Some of the less popular (i.e. I don't use them) utilities could probably do with some TLC or maybe merging into uber-tools if they don't do much. While I haven't drifted too far incompatible just yet, it's getting that way! Speaking of which: cyrus.expunge. It's pretty much all stripped now. I'll be writing something simple in to mailbox_upgrade_index which detects its presence and does a sorted merge of the two files into the new cyrus.index, complete with system_flags & FLAG_EXPUNGED. There's also FLAG_UNLINKED which will allow us to have immediate expunge of the actual on-disk-file (with the associated inabilithy to unexpunge of course!) if sites want that. Thanks for reading! Bron.