Gesaan dan skop
Laksanakan struktur dalam memori dengan set(key, value, timestamp) dan get(key, timestamp). get mengembalikan versi terbaharu untuk kunci tersebut yang cap masanya adalah selewat-lewatnya pada masa pertanyaan; ia mengembalikan status tidak ditemui (miss) yang eksplisit apabila tiada rekod wujud. Jelaskan sama ada cap masa adalah monotonik bagi setiap kunci, sama ada cap masa yang sama saling menulis ganti, sama ada operasi baca dan tulis adalah serentak, dan sama ada pemadaman atau ketahanan (persistence) diperlukan. Terasnya adalah mengekalkan invarian sejarah bagi setiap kunci, bukannya mengisih dan mengimbas setiap rekod secara berulang-ulang.
Perkara yang dinilai penemu duga
Jawapan yang kukuh menyasarkan carian O(log m), dengan m ialah bilangan versi untuk kunci tersebut, dan menjelaskan pertukaran tulis antara penambahan sahaja (append-only) dan input tidak tertib. Penemu duga akan menyelidiki kunci kosong, kedua-dua sempadan masa, cap masa pendua, nilai nol (null), kunci tidak diketahui, dan perbezaan antara versi berkesan terkini dengan versi selepas masa pertanyaan. Tuntutan keselamatan benang (thread-safety) mesti merangkumi keketulan kunci (lock granularity) dan semantik snapshot.
Soalan penjelasan sebelum mengekod
- Adakah cap masa monotonik bagi setiap kunci? Jika ya, tambah di hujung dan gunakan imbasan undur pendek atau carian binari; jika tidak, kekalkan susunan atau tolak penulisan tidak tertib.
- Apakah maksud cap masa yang sama? Untuk dasar penulisan terakhir menang (last-write-wins), kekalkan jujukan yang meningkat secara monotonik sebagai pemutus seri yang stabil; jika tidak, tolak konflik.
- Bolehkah nilai menjadi nol? Jika ya, status tidak ditemui tidak boleh diwakili oleh null juga; kembalikan hasil dengan bendera
foundyang eksplisit. - Adakah keserentakan diperlukan? Selesaikan invarian benang tunggal dahulu, kemudian tentukan keterlihatan dan pilih kunci bagi setiap kunci atau snapshot tidak boleh ubah (immutable).
- Adakah sejarah tidak terhad? Tetingkap pengekalan atau had versi mengubah pengusiran (eviction) dan makna pertanyaan lama.
Rangka kerja jawapan 30 saat
“Saya menyimpan tatasusunan versi yang diisih mengikut masa bagi setiap kunci. get menggunakan upper_bound(timestamp) untuk mencari versi pertama yang lebih besar daripada pertanyaan dan mengembalikan entri sebelumnya, jadi carian ialah O(log m). Jika operasi tulis tidak monotonik, saya menggunakan sisipan bertertib dan menyatakan kosnya; jika daya pemprosesan tulis mendominasi, saya menambah pada log dan membina indeks secara berkelompok. Nombor jujukan menjadikan cap masa yang sama bersifat deterministik, dan keadaan tidak ditemui mempunyai status yang eksplisit. Saya menguji kunci kosong, sempadan, operasi tulis tidak tertib dan cap masa pendua.”
Penyelesaian langkah demi langkah
Wakilkan setiap rekod sebagai (timestamp, sequence, value) dan pastikan tatasusunan setiap kunci tidak berkurangan mengikut (timestamp, sequence). Untuk get(k, t), cari kedudukan pertama i dengan timestamp > t. Jika i ialah sifar, tiada versi yang berkesan; jika tidak, kembalikan records[i - 1]. Peraturan batas atas ini merangkumi penulisan tepat pada t.
Apabila cap masa adalah monotonik bagi setiap kunci, penambahan di hujung memberikan O(1) terlunas untuk set dan O(log m) untuk get. Dengan cap masa tidak tertib, mencari titik sisipan adalah logaritma tetapi menganjak tatasusunan adalah O(m) dalam kes terburuk. Pokok seimbang mengelakkan penganjakan dengan kos peruntukan dan overhed penunjuk yang lebih tinggi. Tatasusunan terisih global tunggal adalah tidak betul kerana sempadan pertanyaan adalah bebas bagi setiap kunci.
Cap masa pendua memerlukan peraturan deterministik. Untuk last-write-wins, berikan setiap panggilan jujukan yang meningkat dan isih mengikut (timestamp, sequence); batas atas hanya membandingkan cap masa, jadi rekod terakhir pada cap masa tersebut akan menang. Jika cap masa boleh melebihi julat integer selamat bahasa, gunakan jenis integer atau pembanding yang sesuai daripada menukarnya secara senyap kepada titik apung.
Untuk keserentakan, peluasan terkecil mengunci satu kunci semasa menggantikan tatasusunan atau menjalankan carian binari. Untuk memastikan operasi baca tidak menyekat (non-blocking), penulis boleh membina tatasusunan tidak boleh ubah yang baharu dan menukar rujukannya secara atomik; pembaca melihat sama ada snapshot lama atau baharu, tidak pernah melihat tatasusunan separa. Ketahanan menambah log, checksum dan kursor pemulihan, dan hanya perlu dibincangkan jika penemu duga meluaskan skop.
Contoh jawapan berkualiti tinggi
“Saya akan menganggap bahawa cap masa mungkin tiba tidak mengikut tertib, cap masa yang sama menggunakan last-write-wins, dan versi pertama adalah benang tunggal. Setiap kunci dipetakan kepada tatasusunan yang diisih mengikut (timestamp, sequence). get melakukan carian batas atas untuk cap masa pertama yang lebih besar daripada pertanyaan dan mengembalikan versi sebelumnya, memberikan carian O(log m) dan tingkah laku kesaksamaan yang betul. Jika cap masa dijamin meningkat, set menjadi O(1) terlunas. Jika operasi tulis mendominasi operasi baca, saya akan menambah pada log dan membina indeks secara tak segerak. Ujian merangkumi kunci tidak diketahui, sebelum versi pertama, sama dengan versi pertama dan terakhir, selepas versi terakhir, penulisan tidak tertib, cap masa pendua dan nilai null.”
Kesilapan lazim
- Kesilapan → mengimbas secara linear untuk versi terakhir; sebab ia gagal → carian menjadi
O(m)dan berskala lemah; pembetulan → kekalkan sejarah terisih dan gunakan carian batas atas. - Kesilapan → gunakan
timestamp < t; sebab ia gagal → penulisan tepat padatditinggalkan; pembetulan → caritimestamp > tyang pertama. - Kesilapan → anggap semua penulisan sentiasa meningkat; sebab ia gagal → peristiwa tidak tertib memecahkan invarian tatasusunan; pembetulan → nyatakan kekangan dan gunakan sisipan bertertib atau pokok.
- Kesilapan → gunakan null untuk status tidak ditemui dan nilai yang disimpan; sebab ia gagal → pemanggil tidak dapat membezakan keadaan; pembetulan → kembalikan
{ found, value }atau jenis pilihan (option) yang eksplisit. - Kesilapan → abaikan cap masa yang sama; sebab ia gagal → hasil bergantung pada susunan sampingan; pembetulan → tambah jujukan atau tolak konflik.
Respons tindakan susulan
Bagaimanakah anda mengoptimumkan jika cap masa dijamin sentiasa meningkat?
Tambah di hujung bagi setiap kunci untuk penulisan terlunas O(1). Kekalkan carian binari untuk bacaan O(log m) yang boleh diramal, atau imbas ke belakang hanya apabila corak akses menunjukkan pertanyaan biasanya berada berhampiran versi terbaharu. Jangan mendakwa bahawa imbasan ke belakang mengambil masa malar dalam kes terburuk.
Bagaimanakah anda mengekalkan hanya 30 hari terakhir bagi setiap kunci?
Tentukan sama ada pemotongan menggunakan masa peristiwa atau masa perkhidmatan, kemudian buang awalan lama secara berkala sambil mengekalkan susunan. Pertanyaan sebelum had pemotongan harus mengembalikan "sejarah tidak tersedia", bukan menyamar sebagai status tidak ditemui biasa.
Apakah yang berubah untuk pembaca dan penulis serentak?
Tentukan titik linearisasi terlebih dahulu. Reka bentuk yang mudah menggunakan kunci baca-tulis (read-write lock) bagi setiap kunci. Untuk bacaan tanpa sekatan (non-blocking), bina tatasusunan baharu dan tukar rujukannya secara atomik supaya pembaca dapat memerhati snapshot lama atau baharu yang lengkap.
Bagaimanakah anda memastikan ketahanan dan pulih selepas kerosakan (crash)?
Tambah pada log berjujukan sebelum mengesahkan penulisan, jana snapshot indeks secara berkala, dan mainkan semula akhiran log selepas pemulihan sambil mengesahkan nombor jujukan. Jangan tambah reka bentuk pangkalan data yang lengkap apabila gesaan hanya meminta pelaksanaan dalam memori.