The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
parcel KinoSearch cnick Kino;

/** Warehouse for information about one segment of an inverted index.
 * 
 * KinoSearch's indexes are made up of individual "segments", each of which is
 * is an independent inverted index.  On the file system, each segment is a
 * directory within the main index directory whose name starts with "seg_":
 * "seg_2", "seg_5a", etc.
 *
 * Each Segment object keeps track of information about an index segment: its
 * fields, document count, and so on.  The Segment object itself writes one
 * file, <code>segmeta.json</code>; besides storing info needed by Segment
 * itself, the "segmeta" file serves as a central repository for metadata
 * generated by other index components -- relieving them of the burden of
 * storing metadata themselves.
 */

class KinoSearch::Index::Segment cnick Seg inherits KinoSearch::Object::Obj {

    CharBuf     *name;
    int64_t      count;
    int64_t      number;
    Hash        *by_name;   /* field numbers by name */
    VArray      *by_num;    /* field names by num */
    Hash        *metadata;

    inert incremented Segment*
    new(int64_t number);

    public inert Segment*
    init(Segment *self, int64_t number);

    /** Return a segment name with a base-36-encoded segment number. 
     */
    inert incremented CharBuf*
    num_to_name(int64_t number);

    /** Return true if the CharBuf is a segment name, i.e. matches this
     * pattern:  /^seg_\w+$/
     */
    inert bool_t
    valid_seg_name(const CharBuf *name);

    /** Register a new field and assign it a field number.  If the field was
     * already known, nothing happens.
     * 
     * @param field Field name.
     * @return the field's field number, which is a positive integer.
     */
    public int32_t
    Add_Field(Segment *self, const CharBuf *field);

    /** Store arbitrary information in the segment's metadata Hash, to be
     * serialized later.  Throws an error if <code>key</code> is used twice.
     *
     * @param key String identifying an index component.
     * @param metadata JSON-izable data structure.
     */
    public void
    Store_Metadata(Segment *self, const CharBuf *key, 
                   decremented Obj *metadata);

    void
    Store_Metadata_Str(Segment *self, const char *key, size_t len, 
                       decremented Obj *value);

    /** Fetch a value from the Segment's metadata hash.
     */
    public nullable Obj*
    Fetch_Metadata(Segment *self, const CharBuf *key);

    nullable Obj*
    Fetch_Metadata_Str(Segment *self, const char *key, size_t len);

    /** Given a field name, return its field number for this segment (which
     * may differ from its number in other segments).  Return 0 (an invalid
     * field number) if the field name can't be found.  
     * 
     * @param field Field name.
     */
    public int32_t
    Field_Num(Segment *self, const CharBuf *field);

    /** Given a field number, return the name of its field, or NULL if the
     * field name can't be found.
     */
    public nullable CharBuf*
    Field_Name(Segment *self, int32_t field_num);

    /** Getter for the object's seg name.
     */
    public CharBuf*
    Get_Name(Segment *self);

    /** Getter for the segment number. 
     */
    public int64_t
    Get_Number(Segment *self);

    /** Setter for the object's document count.
     */
    public void
    Set_Count(Segment *self, int64_t count);

    /** Getter for the object's document count.
     */
    public int64_t 
    Get_Count(Segment *self);

    /** Add <code>increment</code> to the object's document count, then return
     * the new, modified total.
     */
    int64_t
    Increment_Count(Segment *self, int64_t increment);

    /** Get the segment metadata.
     */
    Hash*
    Get_Metadata(Segment *self);

    /** Write the segdata file.
     */
    public void
    Write_File(Segment *self, Folder *folder);

    /** Read the segmeta file for this segment.
     *
     * @return true if the file is read and decoded successfully, false
     * otherwise.
     */
    public bool_t
    Read_File(Segment *self, Folder *folder);

    /** Compare by segment number. 
     */
    public int32_t
    Compare_To(Segment *self, Obj *other);

    public void
    Destroy(Segment *self);
}

/* Copyright 2006-2011 Marvin Humphrey
 *
 * This program is free software; you can redistribute it and/or modify
 * under the same terms as Perl itself.
 */